-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #160 from lil-lab/connect-rds
[recnet-api] Connect environment to rds database and generate DB schema
- Loading branch information
Showing
20 changed files
with
471 additions
and
137 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -55,4 +55,7 @@ Thumbs.db | |
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts | ||
next-env.d.ts | ||
|
||
# recnet-api specific | ||
apps/**/pnpm-lock.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1 @@ | ||
web: pnpm nx deploy recnet-api | ||
web: cd dist/apps/recnet-api && node main.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
version: 0.2 | ||
|
||
phases: | ||
install: | ||
runtime-versions: | ||
nodejs: 18 | ||
commands: | ||
- npm i -g pnpm | ||
- pnpm i --frozen-lockfile | ||
pre_build: | ||
commands: | ||
- pnpm nx clean recnet-api | ||
- pnpm nx prisma:generate recnet-api | ||
build: | ||
commands: | ||
- pnpm nx build recnet-api | ||
post_build: | ||
commands: | ||
- rm -rf node_modules | ||
- cp -R apps/recnet-api/prisma/ dist/apps/recnet-api/prisma | ||
- cd dist/apps/recnet-api | ||
- pnpm install --prod --frozen-lockfile | ||
- pnpx prisma generate --schema=prisma/schema.prisma | ||
|
||
artifacts: | ||
files: | ||
- "dist/apps/recnet-api/**/*" | ||
- "Procfile" | ||
enable-symlinks: yes |
102 changes: 102 additions & 0 deletions
102
apps/recnet-api/prisma/migrations/20240306064817_init/migration.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
-- CreateEnum | ||
CREATE TYPE "Provider" AS ENUM ('FACEBOOK', 'GOOGLE'); | ||
|
||
-- CreateEnum | ||
CREATE TYPE "Role" AS ENUM ('ADMIN', 'USER'); | ||
|
||
-- CreateTable | ||
CREATE TABLE "User" ( | ||
"id" VARCHAR(64) NOT NULL, | ||
"provider" "Provider" NOT NULL, | ||
"providerId" VARCHAR(128) NOT NULL, | ||
"email" VARCHAR(128) NOT NULL, | ||
"handle" VARCHAR(32) NOT NULL, | ||
"displayName" VARCHAR(32) NOT NULL, | ||
"inviteCode" VARCHAR(64), | ||
"photoUrl" VARCHAR(256) NOT NULL, | ||
"affiliation" VARCHAR(32), | ||
"bio" TEXT, | ||
"lastLoginAt" TIMESTAMP(3) NOT NULL, | ||
"role" "Role" NOT NULL DEFAULT 'USER', | ||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
||
CONSTRAINT "User_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateTable | ||
CREATE TABLE "FollowingRecord" ( | ||
"userId" VARCHAR(64) NOT NULL, | ||
"followerId" VARCHAR(64) NOT NULL, | ||
"createdAt" TIMESTAMP(3) NOT NULL, | ||
|
||
CONSTRAINT "FollowingRecord_pkey" PRIMARY KEY ("userId","followerId") | ||
); | ||
|
||
-- CreateTable | ||
CREATE TABLE "Recommendation" ( | ||
"id" VARCHAR(64) NOT NULL, | ||
"userId" VARCHAR(64) NOT NULL, | ||
"articleId" VARCHAR(64) NOT NULL, | ||
"description" TEXT NOT NULL, | ||
"cutoff" TIMESTAMP(3) NOT NULL, | ||
"createAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updateAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
||
CONSTRAINT "Recommendation_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateTable | ||
CREATE TABLE "Article" ( | ||
"id" VARCHAR(64) NOT NULL, | ||
"doi" VARCHAR(32), | ||
"title" VARCHAR(256) NOT NULL, | ||
"author" VARCHAR(256) NOT NULL, | ||
"link" VARCHAR(256) NOT NULL, | ||
"year" SMALLINT NOT NULL, | ||
"month" SMALLINT, | ||
"isVerified" BOOLEAN NOT NULL DEFAULT false, | ||
"createAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"updateAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
|
||
CONSTRAINT "Article_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateTable | ||
CREATE TABLE "InviteCode" ( | ||
"id" SERIAL NOT NULL, | ||
"code" VARCHAR(64) NOT NULL, | ||
"ownerId" VARCHAR(64) NOT NULL, | ||
"issuedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
"usedById" VARCHAR(64), | ||
"usedAt" TIMESTAMP(3), | ||
|
||
CONSTRAINT "InviteCode_pkey" PRIMARY KEY ("id") | ||
); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email"); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "User_handle_key" ON "User"("handle"); | ||
|
||
-- CreateIndex | ||
CREATE UNIQUE INDEX "InviteCode_usedById_key" ON "InviteCode"("usedById"); | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "FollowingRecord" ADD CONSTRAINT "FollowingRecord_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "FollowingRecord" ADD CONSTRAINT "FollowingRecord_followerId_fkey" FOREIGN KEY ("followerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "Recommendation" ADD CONSTRAINT "Recommendation_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "Recommendation" ADD CONSTRAINT "Recommendation_articleId_fkey" FOREIGN KEY ("articleId") REFERENCES "Article"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "InviteCode" ADD CONSTRAINT "InviteCode_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE; | ||
|
||
-- AddForeignKey | ||
ALTER TABLE "InviteCode" ADD CONSTRAINT "InviteCode_usedById_fkey" FOREIGN KEY ("usedById") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# Please do not edit this file manually | ||
# It should be added in your version-control system (i.e. Git) | ||
provider = "postgresql" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
// This is your Prisma schema file, | ||
// learn more about it in the docs: https://pris.ly/d/prisma-schema | ||
|
||
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions? | ||
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init | ||
|
||
generator client { | ||
provider = "prisma-client-js" | ||
} | ||
|
||
datasource db { | ||
provider = "postgresql" | ||
url = env("PRISMA_DATABASE_URL") | ||
} | ||
|
||
// Define enum types | ||
enum Provider { | ||
// Add other providers here as needed | ||
} | ||
|
||
enum Role { | ||
ADMIN | ||
USER | ||
} | ||
|
||
model User { | ||
id String @id @db.VarChar(64) @default(uuid()) // Primary key, UUID type | ||
provider Provider // Enum type | ||
providerId String @db.VarChar(128) | ||
email String @db.VarChar(128) @unique | ||
handle String @db.VarChar(32) @unique | ||
displayName String @db.VarChar(32) | ||
inviteCode String? @db.VarChar(64) | ||
photoUrl String @db.VarChar(256) | ||
affiliation String? @db.VarChar(32) | ||
bio String? | ||
lastLoginAt DateTime | ||
role Role @default(USER) // Enum type | ||
createdAt DateTime @default(now()) | ||
updatedAt DateTime @default(now()) @updatedAt | ||
following FollowingRecord[] @relation("Following") | ||
followers FollowingRecord[] @relation("Follower") | ||
recommendations Recommendation[] | ||
inviteCodeOwner InviteCode[] @relation("InviteCodeOwner") | ||
inviteCodeUsed InviteCode? @relation("InviteCodeUsedBy") | ||
} | ||
|
||
model FollowingRecord { | ||
userId String @db.VarChar(64) | ||
followerId String @db.VarChar(64) | ||
createdAt DateTime | ||
@@id([userId, followerId]) | ||
user User @relation("Following", fields: [userId], references: [id]) | ||
follower User @relation("Follower", fields: [followerId], references: [id]) | ||
} | ||
|
||
model Recommendation { | ||
id String @id @db.VarChar(64) @default(uuid()) | ||
userId String @db.VarChar(64) | ||
articleId String @db.VarChar(64) | ||
description String | ||
cutoff DateTime | ||
createAt DateTime @default(now()) | ||
updateAt DateTime @default(now()) @updatedAt | ||
user User @relation(fields: [userId], references: [id]) // User who made the recommendation | ||
article Article @relation(fields: [articleId], references: [id]) // Article being recommended | ||
} | ||
|
||
model Article { | ||
id String @id @db.VarChar(64) @default(uuid()) | ||
doi String? @db.VarChar(32) | ||
title String @db.VarChar(256) | ||
author String @db.VarChar(256) | ||
link String @db.VarChar(256) | ||
year Int @db.SmallInt | ||
month Int? @db.SmallInt | ||
isVerified Boolean @default(false) | ||
createAt DateTime @default(now()) | ||
updateAt DateTime @default(now()) @updatedAt | ||
recommendations Recommendation[] | ||
} | ||
|
||
model InviteCode { | ||
id Int @id @default(autoincrement()) | ||
code String @db.VarChar(64) | ||
ownerId String @db.VarChar(64) | ||
issuedAt DateTime @default(now()) | ||
usedById String? @db.VarChar(64) @unique | ||
usedAt DateTime? | ||
owner User @relation("InviteCodeOwner", fields: [ownerId], references: [id]) | ||
usedBy User? @relation("InviteCodeUsedBy", fields: [usedById], references: [id]) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
53 changes: 53 additions & 0 deletions
53
apps/recnet-api/src/database/prisma/prisma.connection.provider.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
import { execSync } from "child_process"; | ||
|
||
import { Injectable, OnModuleInit } from "@nestjs/common"; | ||
import { PrismaClient } from "@prisma/client"; | ||
|
||
const postgresConfig = { | ||
host: process.env.RDS_HOSTNAME, | ||
port: parseInt(process.env.RDS_PORT, 10), | ||
database: process.env.RDS_DB_NAME, | ||
username: process.env.RDS_USERNAME, | ||
password: process.env.RDS_PASSWORD, | ||
}; | ||
|
||
@Injectable() | ||
export class PrismaConnectionProvider | ||
extends PrismaClient | ||
implements OnModuleInit | ||
{ | ||
private prismaUrl: string; | ||
|
||
constructor() { | ||
const connectionUrl = `postgresql://${postgresConfig.username}:${encodeURIComponent( | ||
postgresConfig.password | ||
)}@${postgresConfig.host}:${postgresConfig.port}/${ | ||
postgresConfig.database | ||
}?schema=recnet`; | ||
|
||
super({ | ||
datasources: { | ||
db: { | ||
url: `${connectionUrl}&pool_timeout=60`, | ||
}, | ||
}, | ||
}); | ||
|
||
this.prismaUrl = connectionUrl; | ||
} | ||
|
||
async onModuleInit() { | ||
await this.$connect(); | ||
|
||
const prismaSchema = process.env.PRISMA_SCHEMA || "prisma/schema.prisma"; | ||
|
||
if (process.env.DB_MIGRATE === "true") { | ||
execSync( | ||
`export PRISMA_DATABASE_URL=${this.prismaUrl} && pnpx prisma migrate deploy --schema=${prismaSchema}`, | ||
{ stdio: "inherit" } | ||
); | ||
} | ||
} | ||
} | ||
|
||
export default PrismaConnectionProvider; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Module } from "@nestjs/common"; | ||
|
||
import PrismaConnectionProvider from "./prisma.connection.provider"; | ||
|
||
@Module({ | ||
providers: [PrismaConnectionProvider], | ||
exports: [PrismaConnectionProvider], | ||
}) | ||
export class PrismaModule {} |
11 changes: 11 additions & 0 deletions
11
apps/recnet-api/src/database/repository/db.repository.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { Module } from "@nestjs/common"; | ||
|
||
import UserRepository from "./user.repository"; | ||
import { PrismaModule } from "../prisma/prisma.module"; | ||
|
||
@Module({ | ||
imports: [PrismaModule], | ||
providers: [UserRepository], | ||
exports: [UserRepository], | ||
}) | ||
export class DbRepositoryModule {} |
15 changes: 15 additions & 0 deletions
15
apps/recnet-api/src/database/repository/user.repository.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { Injectable } from "@nestjs/common"; | ||
import { User } from "@prisma/client"; | ||
|
||
import PrismaConnectionProvider from "src/database/prisma/prisma.connection.provider"; | ||
|
||
@Injectable() | ||
export default class UserRepository { | ||
constructor(private readonly prisma: PrismaConnectionProvider) {} | ||
|
||
public async findByHandle(handle: string): Promise<User> { | ||
return this.prisma.user.findFirst({ | ||
where: { handle }, | ||
}); | ||
} | ||
} |
Oops, something went wrong.