Adds database connection logic
This commit is contained in:
parent
fe0cd10c36
commit
653f1f007b
18
docker-compose.yml
Normal file
18
docker-compose.yml
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:17
|
||||||
|
container_name: molci-db
|
||||||
|
restart: unless-stopped
|
||||||
|
env_file:
|
||||||
|
- ./server/.env
|
||||||
|
environment:
|
||||||
|
POSTGRES_USER: ${DB_USER}
|
||||||
|
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||||
|
POSTGRES_DB: ${DB_NAME}
|
||||||
|
ports:
|
||||||
|
- "5432:5432"
|
||||||
|
volumes:
|
||||||
|
- postgres_data:/var/lib/postgresql/data
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
postgres_data:
|
||||||
34
server/biome.json
Normal file
34
server/biome.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/2.2.0/schema.json",
|
||||||
|
"vcs": {
|
||||||
|
"enabled": false,
|
||||||
|
"clientKind": "git",
|
||||||
|
"useIgnoreFile": false
|
||||||
|
},
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": false
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "tab"
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "double"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"assist": {
|
||||||
|
"enabled": true,
|
||||||
|
"actions": {
|
||||||
|
"source": {
|
||||||
|
"organizeImports": "on"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,33 @@
|
|||||||
{
|
{
|
||||||
"name": "server",
|
"name": "server",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"dev": "tsx --watch --env-file .env src/index.ts",
|
||||||
},
|
"watch": "tsx watch src/index.ts",
|
||||||
"keywords": [],
|
"check": "tsc --noEmit",
|
||||||
"author": "",
|
"build": "tsc",
|
||||||
"license": "ISC",
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
"packageManager": "pnpm@10.15.0"
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"packageManager": "pnpm@10.15.0",
|
||||||
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "2.2.0",
|
||||||
|
"@tsconfig/strictest": "^2.0.5",
|
||||||
|
"@types/express": "^5.0.3",
|
||||||
|
"@types/jest": "^30.0.0",
|
||||||
|
"@types/node": "^24.3.0",
|
||||||
|
"@types/pg": "^8.15.5",
|
||||||
|
"jest": "^30.0.5",
|
||||||
|
"ts-jest": "^29.4.1",
|
||||||
|
"tsx": "^4.20.4",
|
||||||
|
"typescript": "^5.9.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"pg": "^8.16.3"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4020
server/pnpm-lock.yaml
generated
Normal file
4020
server/pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
30
server/src/config/db.ts
Normal file
30
server/src/config/db.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { Pool } from "pg";
|
||||||
|
import { config } from "./env";
|
||||||
|
|
||||||
|
let pool: Pool;
|
||||||
|
|
||||||
|
const { DB_USER, DB_PASSWORD, DB_NAME } = config;
|
||||||
|
|
||||||
|
if (!DB_USER || !DB_PASSWORD || !DB_NAME) {
|
||||||
|
throw new Error("DB_USER, DB_PASSWORD, and DB_NAME must be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
pool = new Pool({
|
||||||
|
user: config.DB_USER,
|
||||||
|
host: config.DB_HOST,
|
||||||
|
database: config.DB_NAME,
|
||||||
|
password: config.DB_PASSWORD,
|
||||||
|
port: config.DB_PORT,
|
||||||
|
});
|
||||||
|
|
||||||
|
const connectDB = async () => {
|
||||||
|
try {
|
||||||
|
await pool.connect();
|
||||||
|
console.log("PostgreSQL DATABASE connected");
|
||||||
|
} catch (err) {
|
||||||
|
const error = err as Error;
|
||||||
|
console.error("DB connection error:", error.stack || error.message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export { pool, connectDB };
|
||||||
33
server/src/config/env.ts
Normal file
33
server/src/config/env.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
type EnvMode = "development" | "production" | "test";
|
||||||
|
|
||||||
|
interface ProcessEnv {
|
||||||
|
NODE_ENV?: EnvMode;
|
||||||
|
APP_PORT?: string;
|
||||||
|
DB_USER: string;
|
||||||
|
DB_PASSWORD: string;
|
||||||
|
DB_HOST?: string;
|
||||||
|
DB_NAME: string;
|
||||||
|
DB_PORT?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = process.env as unknown as ProcessEnv;
|
||||||
|
|
||||||
|
function requiredEnv(key: keyof ProcessEnv): string {
|
||||||
|
const value = env[key];
|
||||||
|
if (!value) {
|
||||||
|
throw new Error(`Missing required environment variable: ${key}`);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const config = {
|
||||||
|
NODE_ENV: env.NODE_ENV ?? "development",
|
||||||
|
APP_PORT: env.APP_PORT ? Number(env.APP_PORT) : 3000,
|
||||||
|
DB_HOST: env.DB_HOST ?? "localhost",
|
||||||
|
DB_NAME: requiredEnv("DB_NAME"),
|
||||||
|
DB_USER: requiredEnv("DB_USER"),
|
||||||
|
DB_PASSWORD: requiredEnv("DB_PASSWORD"),
|
||||||
|
DB_PORT: env.DB_PORT ? Number(env.DB_PORT) : 5432,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const isProduction = config.NODE_ENV === "production";
|
||||||
26
server/src/index.ts
Normal file
26
server/src/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import express from "express";
|
||||||
|
import { pool } from "./config/db";
|
||||||
|
import { config, isProduction } from "./config/env";
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
const PORT = config.APP_PORT;
|
||||||
|
|
||||||
|
app.use(express.json());
|
||||||
|
|
||||||
|
app.get("/ping", async (_req, res) => {
|
||||||
|
try {
|
||||||
|
const result = await pool.query("SELECT NOW()");
|
||||||
|
res.json({ success: true, time: result.rows[0].now });
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Database error:", error);
|
||||||
|
res
|
||||||
|
.status(500)
|
||||||
|
.json({ success: false, error: "Database connection failed" });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(PORT, () => {
|
||||||
|
console.log(
|
||||||
|
`Server running in ${isProduction ? "production" : "development"} mode on port ${PORT}`,
|
||||||
|
);
|
||||||
|
});
|
||||||
29
server/tsconfig.json
Normal file
29
server/tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/strictest/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist",
|
||||||
|
"strict": true,
|
||||||
|
"allowUnusedLabels": false,
|
||||||
|
"allowUnreachableCode": false,
|
||||||
|
"exactOptionalPropertyTypes": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noPropertyAccessFromIndexSignature": true,
|
||||||
|
"noUncheckedIndexedAccess": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noUnusedParameters": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules", "dist"],
|
||||||
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"_version": "2.0.0"
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user