From 3c8bdac34f82679b5b3222d6bc1be29013d10439 Mon Sep 17 00:00:00 2001 From: eneller Date: Fri, 6 Mar 2026 00:52:27 +0100 Subject: [PATCH] feat: basic db connection --- .../screen-profile/screen-profile.html | 2 +- .../screens/screen-profile/screen-profile.ts | 1 + package-lock.json | 51 +++++++++++++------ server/compose.yml | 17 +++++++ server/package.json | 10 ++-- server/src/db.ts | 28 ++++++++-- server/src/index.ts | 18 ++++++- 7 files changed, 101 insertions(+), 26 deletions(-) create mode 100644 server/compose.yml diff --git a/client/src/app/screens/screen-profile/screen-profile.html b/client/src/app/screens/screen-profile/screen-profile.html index 32123e4..d3ca5c9 100644 --- a/client/src/app/screens/screen-profile/screen-profile.html +++ b/client/src/app/screens/screen-profile/screen-profile.html @@ -19,7 +19,7 @@
- @for (transaction of transactions; track transaction.date) { + @for (transaction of transactions; track $index) {
diff --git a/client/src/app/screens/screen-profile/screen-profile.ts b/client/src/app/screens/screen-profile/screen-profile.ts index 6d0bef7..d960249 100644 --- a/client/src/app/screens/screen-profile/screen-profile.ts +++ b/client/src/app/screens/screen-profile/screen-profile.ts @@ -17,6 +17,7 @@ export class ScreenProfile implements OnInit{ constructor(private api: APIService){} ngOnInit(): void { + // FIXME transactions displaying delayed (only on second nav click) this.api.getTransactions().subscribe({ next: (transactions) => { this.transactions = transactions; diff --git a/package-lock.json b/package-lock.json index aa0babb..425adaa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8614,14 +8614,14 @@ "license": "MIT" }, "node_modules/pg": { - "version": "8.19.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.19.0.tgz", - "integrity": "sha512-QIcLGi508BAHkQ3pJNptsFz5WQMlpGbuBGBaIaXsWK8mel2kQ/rThYI+DbgjUvZrIr7MiuEuc9LcChJoEZK1xQ==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", "license": "MIT", "dependencies": { - "pg-connection-string": "^2.11.0", - "pg-pool": "^3.12.0", - "pg-protocol": "^1.12.0", + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, @@ -8648,11 +8648,23 @@ "optional": true }, "node_modules/pg-connection-string": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz", - "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ==", + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", "license": "MIT" }, + "node_modules/pg-hstore": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.4.tgz", + "integrity": "sha512-N3SGs/Rf+xA1M2/n0JBiXFDVMzdekwLZLAO0g7mpDY9ouX+fDI7jS6kTq3JujmYbtNSJ53TJ0q4G98KVZSM4EA==", + "license": "MIT", + "dependencies": { + "underscore": "^1.13.1" + }, + "engines": { + "node": ">= 0.8.x" + } + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -8663,18 +8675,18 @@ } }, "node_modules/pg-pool": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.12.0.tgz", - "integrity": "sha512-eIJ0DES8BLaziFHW7VgJEBPi5hg3Nyng5iKpYtj3wbcAUV9A1wLgWiY7ajf/f/oO1wfxt83phXPY8Emztg7ITg==", + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", "license": "MIT", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-protocol": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.12.0.tgz", - "integrity": "sha512-uOANXNRACNdElMXJ0tPz6RBM0XQ61nONGAwlt8da5zs/iUOOCLBQOHSXnrC6fMsvtjxbOJrZZl5IScGv+7mpbg==", + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", "license": "MIT" }, "node_modules/pg-types": { @@ -10209,6 +10221,12 @@ "dev": true, "license": "MIT" }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "license": "MIT" + }, "node_modules/undici": { "version": "7.22.0", "resolved": "https://registry.npmjs.org/undici/-/undici-7.22.0.tgz", @@ -10870,7 +10888,8 @@ "cors": "^2.8.6", "dotenv": "^17.3.1", "express": "^5.2.1", - "pg": "^8.19.0", + "pg": "^8.20.0", + "pg-hstore": "^2.3.4", "sequelize": "^6.37.7" }, "devDependencies": { diff --git a/server/compose.yml b/server/compose.yml new file mode 100644 index 0000000..bda9fa5 --- /dev/null +++ b/server/compose.yml @@ -0,0 +1,17 @@ +services: + postgres: + image: postgres + environment: + POSTGRES_PASSWORD: pass + ports: + - "5432:5432" + + adminer: + image: adminer + restart: always + environment: + ADMINER_DEFAULT_SERVER: postgres # Automatically connect to the "postgres" service + ports: + - "8080:8080" + depends_on: + - postgres # Ensure PostgreSQL starts first diff --git a/server/package.json b/server/package.json index 4a30118..2f9e457 100644 --- a/server/package.json +++ b/server/package.json @@ -8,16 +8,20 @@ "main": "../dist/out-tsc/server/index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "dev": "nodemon", + "node": "nodemon", "start": "ts-node src/index.ts", "build": "tsc", - "serve": "node ../dist/out-tsc/server/index.js" + "serve": "node ../dist/out-tsc/server/index.js", + "setup": "docker compose up -d", + "teardown": "docker compose down", + "dev": "npm run setup && npm run node; npm run teardown" }, "dependencies": { "cors": "^2.8.6", "dotenv": "^17.3.1", "express": "^5.2.1", - "pg": "^8.19.0", + "pg": "^8.20.0", + "pg-hstore": "^2.3.4", "sequelize": "^6.37.7" }, "devDependencies": { diff --git a/server/src/db.ts b/server/src/db.ts index 40f3fd2..cff6258 100644 --- a/server/src/db.ts +++ b/server/src/db.ts @@ -1,7 +1,27 @@ -const { Pool } = require("pg"); +import { Sequelize } from 'sequelize'; +import { Transaction } from '@shared/interfaces/transaction' -const pool = new Pool({ - connectionString: process.env.DATABASE_URL, +// Initialize Sequelize +const db = new Sequelize({ + dialect: 'postgres', + host: process.env.DB_HOST || 'localhost', + port: parseInt(process.env.DB_PORT || '5432'), + database: process.env.DB_NAME || 'postgres', + username: process.env.DB_USER || 'postgres', + password: process.env.DB_PASSWORD || 'pass', + logging: false, // Disable logging in production }); -module.exports = pool; +// Test the connection +async function testConnection() { + try { + await db.authenticate(); + console.log('✅ Database connection established.'); + } catch (err) { + console.error('❌ Unable to connect to the database:', err); + process.exit(1); // Exit if DB connection fails + } +} + +// Export Sequelize instance and models +export { db, testConnection }; diff --git a/server/src/index.ts b/server/src/index.ts index ec51312..6c69f4b 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -2,6 +2,7 @@ import express, { Express, Request, Response } from "express"; import cors from "cors"; import * as dotenv from "dotenv"; import transactionsRouter from './routes/transactions'; +import { db, testConnection } from "./db"; dotenv.config(); @@ -17,6 +18,19 @@ app.get("/api/health", (req: Request, res: Response) => { app.use('/api/transactions', transactionsRouter); const PORT: number = parseInt(process.env.PORT as string) || 3000; -app.listen(PORT, () => { - console.log(`Server running on port ${PORT}`); + +// Start server after DB connection is established +async function startServer() { + await testConnection(); // Test DB connection first + + // Sync models (use migrations in production!) + await db.sync({ alter: true }); // Use { force: true } to drop and recreate tables (development only!) + + app.listen(PORT, () => { + console.log(`🚀 Server running on http://localhost:${PORT}`); + }); +} +startServer().catch((err) => { + console.error('Failed to start server:', err); + process.exit(1); });