Skip to content

Commit 2e37604

Browse files
committed
feat: migrate to PostgreSQL + Prisma
1 parent d11e3cd commit 2e37604

31 files changed

+401
-418
lines changed

.dockerignore

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
.env
22
.envrc
3+
node_modules
4+
35
.husky
46
.github
7+
.vscode
8+
*.md
9+
Makefile
510
.prettierrc
611
jest.config.js
7-
*.md
8-
node_modules
912
/lib
1013
/src/**/*.test.ts
1114
/tmp
1215
/data
13-
*.tsbuildinfo
16+
*.tsbuildinfo

.env.placeholder .env.example

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1+
LIFETIME=
12
JWT_SECRET=
23

34
DISCORD_CLIENT_ID=
45
DISCORD_CLIENT_SECRET=
5-
66
DISCORD_TOKEN=
77
DISCORD_GUILD_ID=
88

9-
HB_MONGO_URI=
9+
HONEYBEE_URI=
10+
HONEYBEE_REAL_IP=
11+
1012
HB_TEST_CHANNEL_ID=
1113
HB_TEST_ORIGIN_CHANNEL_ID=
1214
HB_TEST_ORIGIN_CHANNEL_ID_NE=

CONTRIBUTING.md

+12-2
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,22 @@
33
## Development Guide
44

55
```bash
6-
git clone https://github.com/holodata/ShipID.git && cd ShipID
6+
# clone repo
7+
git clone https://github.com/holodata/ShipID.git
8+
cd ShipID
79
npm install
10+
11+
# setup .env
812
cp .env.placeholder .env
913
vim .env
10-
npm run devcontainer
1114

15+
# deploy commands
16+
npm run deploy-commands
17+
18+
# fire up dev containers
19+
docker compose up --build
20+
21+
docker compose exec bot yarn prisma db push
1222
```
1323

1424
## Deploy Guide (Maintainers only)

Dockerfile

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ COPY package.json yarn.lock ./
55
RUN yarn install --frozen-lockfile
66

77
COPY . .
8+
RUN yarn prisma generate
89
RUN yarn build
910

1011
CMD ["node", "./lib/index.js"]

docker-compose.production.yml

+7-5
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,25 @@
11
version: "3.1"
22

33
services:
4-
mongo:
5-
image: mongo:4
6-
restart: unless-stopped
4+
postgres:
5+
image: postgres:12
6+
# environment:
7+
# POSTGRES_HOST_AUTH_METHOD: trust
78
volumes:
8-
- ./data/mongo:/data/db
9+
- ./data/postgres:/var/lib/postgresql/data
910

1011
bot:
1112
build: .
1213
restart: unless-stopped
1314
command: node .
1415
env_file: .env
1516
environment:
16-
MONGODB_URL: mongodb://mongo:27017/shipid
1717
NODE_ENV: production
1818
networks:
1919
- default
2020
- webproxy
21+
depends_on:
22+
- postgres
2123

2224
networks:
2325
webproxy:

docker-compose.yml

+16-9
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,29 @@
11
version: "3.1"
22

33
services:
4-
mongo:
5-
image: mongo:4
4+
postgres:
5+
image: postgres:12
6+
environment:
7+
POSTGRES_HOST_AUTH_METHOD: trust
8+
ports:
9+
- 5432:5432
610
volumes:
7-
- ./data/mongo:/data/db
11+
- ./data/postgres:/var/lib/postgresql/data
812

913
bot:
1014
build: .
1115
command: yarn dev
16+
env_file: .env
17+
environment:
18+
DATABASE_URL: postgresql://postgres@postgres:5432/postgres
19+
DEBUG: shipid
1220
ports:
13-
- "3000:3000"
21+
- 3000:3000
1422
volumes:
1523
- ./lib:/app/lib
1624
- ./src:/app/src
17-
env_file: .env
18-
environment:
19-
MONGODB_URL: mongodb://mongo:27017/shipid
20-
DEBUG: shipid
25+
- ./prisma:/app/prisma
2126
depends_on:
22-
- mongo
27+
- postgres
28+
extra_hosts:
29+
- mongo:${HONEYBEE_REAL_IP}

package.json

+11-13
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,9 @@
88
"clean": "shx rm -rf lib && docker-compose -f docker-compose.production.yml down --rmi local",
99
"deploy-commands": "ts-node src/discord/deploy-commands.ts",
1010
"dev": "run-p dev:*",
11-
"dev:prisma": "nodemon -w prisma/schema.prisma -x prisma generate",
11+
"dev:prisma": "prisma generate --watch",
1212
"dev:server": "nodemon -w lib .",
13-
"dev:tsc": "tsc -w",
14-
"devcontainer": "docker-compose up | grep -v mongo_1",
15-
"predevcontainer": "npm run deploy-commands",
13+
"dev:tsc": "tsc -w --preserveWatchOutput",
1614
"prepare": "husky install",
1715
"start": "node ."
1816
},
@@ -21,29 +19,29 @@
2119
"lib"
2220
],
2321
"dependencies": {
24-
"@discordjs/builders": "^0.15.0",
25-
"@discordjs/rest": "^0.5.0",
22+
"@discordjs/builders": "^1.0.0",
23+
"@discordjs/rest": "^1.0.0",
2624
"@prisma/client": "^4.0.0",
2725
"@typegoose/typegoose": "^9.10.1",
26+
"axios": "^0.27.2",
27+
"chalk": "^4",
2828
"debug": "^4.3.4",
29-
"discord-api-types": "^0.36.1",
30-
"discord.js": "^13.8.1",
29+
"discord-api-types": "^0.36.2",
30+
"discord.js": "^14.0.2",
3131
"express": "^4.18.1",
3232
"jsonwebtoken": "^8.5.1",
3333
"luxon": "^3.0.1",
3434
"mongoose": "~6.4.4",
35-
"node-fetch": "3.2.7",
3635
"node-schedule": "^2.1.0",
3736
"prisma": "^4.0.0"
3837
},
3938
"devDependencies": {
4039
"@types/debug": "^4.1.7",
4140
"@types/express": "^4.17.13",
42-
"@types/jest": "^28.1.4",
41+
"@types/jest": "^28.1.6",
4342
"@types/jsonwebtoken": "^8.5.8",
4443
"@types/luxon": "^2.3.2",
45-
"@types/node": "^18.0.3",
46-
"@types/node-fetch": "2.6.2",
44+
"@types/node": "^18.0.6",
4745
"@types/node-schedule": "^2.1.0",
4846
"husky": "^8.0.1",
4947
"masterchat": "^1.1.0",
@@ -52,7 +50,7 @@
5250
"prettier": "^2.7.1",
5351
"pretty-quick": "^3.1.3",
5452
"shx": "^0.3.4",
55-
"ts-node": "^10.8.2",
53+
"ts-node": "^10.9.1",
5654
"typescript": "^4.7.4"
5755
},
5856
"homepage": "https://github.com/holodata/shipid",

prisma/schema.prisma

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
datasource db {
2+
provider = "postgresql"
3+
url = env("DATABASE_URL")
4+
}
5+
6+
generator client {
7+
provider = "prisma-client-js"
8+
}
9+
10+
model User {
11+
discordId String @id
12+
youtubeChannelId String?
13+
attestations Attestation[]
14+
}
15+
16+
model Tie {
17+
guildId String // Target guild id
18+
roleId String // Member role
19+
originChannelId String // Target YT channel
20+
21+
@@id([guildId, roleId, originChannelId])
22+
}
23+
24+
model Attestation {
25+
id Int @id @default(autoincrement())
26+
attestedAt DateTime @default(now())
27+
valid Boolean
28+
since String?
29+
originChannelId String
30+
user User @relation(fields: [userDiscordId], references: [discordId])
31+
userDiscordId String
32+
33+
@@unique([userDiscordId, originChannelId])
34+
}

src/constants.ts

+2-5
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,8 @@ assert(DISCORD_CLIENT_SECRET, "DISCORD_TOKEN is missing");
1616
export const DISCORD_TOKEN = process.env.DISCORD_TOKEN!;
1717
assert(DISCORD_TOKEN, "DISCORD_TOKEN is missing");
1818

19-
export const MONGODB_URL = process.env.MONGODB_URL!;
20-
if (!isDev) assert(MONGODB_URL, "MONGODB_URL is missing");
21-
22-
export const HB_MONGO_URI = process.env.HB_MONGO_URI!;
23-
if (!isDev) assert(HB_MONGO_URI);
19+
export const HONEYBEE_URI = process.env.HONEYBEE_URI!;
20+
if (!isDev) assert(HONEYBEE_URI);
2421

2522
export const PORT = Number(process.env.PORT || 3000);
2623

src/db.ts

+40-29
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import PairModel, { Pair } from "./models/pair";
2-
import UserModel, { User } from "./models/user";
3-
import CertificateModel, { Certificate } from "./models/certificate";
1+
import { Attestation, PrismaClient, Tie, User } from "@prisma/client";
2+
3+
const client = new PrismaClient();
44

55
export async function getUserByDiscordId(discordId: string) {
6-
return await UserModel.findOne({ discordId });
6+
return await client.user.findFirst({ where: { discordId } });
77
}
88

99
export async function createOrUpdateUser({
@@ -13,18 +13,16 @@ export async function createOrUpdateUser({
1313
discordId: string;
1414
youtubeChannelId: string;
1515
}) {
16-
const user = await getUserByDiscordId(discordId);
17-
if (user) {
18-
user.youtubeChannelId = youtubeChannelId;
19-
return await user.save();
20-
}
21-
22-
const newUser = await UserModel.create({
23-
discordId,
24-
youtubeChannelId,
16+
const newOrUpdatedUser = await client.user.upsert({
17+
where: { discordId },
18+
update: { youtubeChannelId },
19+
create: {
20+
discordId,
21+
youtubeChannelId,
22+
},
2523
});
2624

27-
return newUser;
25+
return newOrUpdatedUser;
2826
}
2927

3028
export async function createPair({
@@ -35,13 +33,15 @@ export async function createPair({
3533
guildId: string;
3634
roleId: string;
3735
originChannelId: string;
38-
}): Promise<Pair> {
39-
const pair = await PairModel.create({ guildId, roleId, originChannelId });
36+
}): Promise<Tie> {
37+
const pair = await client.tie.create({
38+
data: { guildId, roleId, originChannelId },
39+
});
4040
return pair;
4141
}
4242

43-
export async function getPairsForGuild(guildId: string): Promise<Pair[]> {
44-
const pairs = await PairModel.find({ guildId });
43+
export async function getPairsForGuild(guildId: string): Promise<Tie[]> {
44+
const pairs = await client.tie.findMany({ where: { guildId } });
4545
return pairs;
4646
}
4747

@@ -51,8 +51,10 @@ export async function findCertificate({
5151
}: {
5252
user: User;
5353
originChannelId: string;
54-
}): Promise<Certificate | null> {
55-
return await CertificateModel.findOne({ user, originChannelId });
54+
}): Promise<Attestation | null> {
55+
return await client.attestation.findFirst({
56+
where: { user, originChannelId },
57+
});
5658
}
5759

5860
export interface ModifyOptions {
@@ -67,19 +69,28 @@ export async function createOrUpdateCertificate({
6769
originChannelId,
6870
valid,
6971
since,
70-
}: ModifyOptions): Promise<Certificate> {
72+
}: ModifyOptions): Promise<Attestation> {
7173
const cert = await findCertificate({ user, originChannelId });
7274
if (cert) {
73-
cert.valid = valid;
74-
cert.since = since;
75-
return await cert.save();
75+
const updated = await client.attestation.update({
76+
where: { id: cert.id },
77+
data: {
78+
valid,
79+
since: since ?? null,
80+
},
81+
});
82+
return updated;
7683
}
7784

78-
const newCert = await CertificateModel.create({
79-
user,
80-
originChannelId,
81-
valid,
82-
since,
85+
const newCert = await client.attestation.create({
86+
data: {
87+
user: {
88+
connect: user,
89+
},
90+
originChannelId,
91+
valid,
92+
since,
93+
},
8394
});
8495

8596
return newCert;

0 commit comments

Comments
 (0)