From c6d68334bef572e174f3e04f4ae5df5412473c46 Mon Sep 17 00:00:00 2001 From: tuffahni Date: Mon, 30 Dec 2024 04:14:32 +0000 Subject: [PATCH] lesson 8 --- nodeJS/Learning/06/docker-compose.yaml | 36 ++++- nodeJS/Learning/06/package.json | 4 +- nodeJS/Learning/06/pnpm-lock.yaml | 178 +++++++++++++++++++++++++ nodeJS/Learning/06/public/js/index.js | 0 nodeJS/Learning/06/src/database/pg.ts | 14 ++ nodeJS/Learning/06/src/index.ts | 85 +++++++++++- nodeJS/Learning/06/src/views/index.ejs | 11 +- 7 files changed, 320 insertions(+), 8 deletions(-) create mode 100644 nodeJS/Learning/06/public/js/index.js create mode 100644 nodeJS/Learning/06/src/database/pg.ts diff --git a/nodeJS/Learning/06/docker-compose.yaml b/nodeJS/Learning/06/docker-compose.yaml index 3fda7d1..74b6f13 100644 --- a/nodeJS/Learning/06/docker-compose.yaml +++ b/nodeJS/Learning/06/docker-compose.yaml @@ -3,8 +3,42 @@ services: build: . ports: - "3000:3000" + # files are put in here volumes: - .:/usr/src/app - ./node_modules:/usr/src/app/node_modules command: ["yarn", "dev"] - # Database + + # Database: how we want to create the database + db: + # Image of postgres in 13th version + image: postgres:13 + environment: #secret + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: ${DB_NAME} + ports: #internally the port is 5432, but we want to use 5432 locally + - "5432:5432" + # create a file to store stuff, store inside "data" folder + volumes: + - ./data:/var/lib/postgresql/data + + # PGAdmin: visualize postgres database + pgadmin: + image: dpage/pgadmin4 + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_DEFAULT_EMAIL} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_DEFAULT_PASSWORD} + ports: + # our local port is 3001, but the container port is 80 + - "3001:80" + # creating a folder called pgadmin to store the pgadmin files + volumes: + - ./pgadmin:/root/.pgadmin + depends_on: + - db + +# tell docker to create something called data (refer to above) and store all the postgres data in it +volumes: + data: + pgadmin: diff --git a/nodeJS/Learning/06/package.json b/nodeJS/Learning/06/package.json index deb1a26..26f9832 100644 --- a/nodeJS/Learning/06/package.json +++ b/nodeJS/Learning/06/package.json @@ -11,10 +11,12 @@ "dependencies": { "dotenv": "^16.4.7", "ejs": "^3.1.10", - "express": "^4.21.2" + "express": "^4.21.2", + "pg": "^8.13.1" }, "devDependencies": { "@types/express": "^5.0.0", + "@types/pg": "^8.11.10", "concurrently": "^9.1.1", "nodemon": "^3.1.9", "sass": "^1.83.0", diff --git a/nodeJS/Learning/06/pnpm-lock.yaml b/nodeJS/Learning/06/pnpm-lock.yaml index 1d0dea5..e3dbec8 100644 --- a/nodeJS/Learning/06/pnpm-lock.yaml +++ b/nodeJS/Learning/06/pnpm-lock.yaml @@ -17,10 +17,16 @@ importers: express: specifier: ^4.21.2 version: 4.21.2 + pg: + specifier: ^8.13.1 + version: 8.13.1 devDependencies: '@types/express': specifier: ^5.0.0 version: 5.0.0 + '@types/pg': + specifier: ^8.11.10 + version: 8.11.10 concurrently: specifier: ^9.1.1 version: 9.1.1 @@ -168,6 +174,9 @@ packages: '@types/node@22.10.2': resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} + '@types/pg@8.11.10': + resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==} + '@types/qs@6.9.17': resolution: {integrity: sha512-rX4/bPcfmvxHDv0XjfJELTTr+iB+tn032nPILqHm5wbthUUUuVtNGGqzhya9XUxjTP8Fpr0qYgSZZKxGY++svQ==} @@ -560,6 +569,9 @@ packages: resolution: {integrity: sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==} engines: {node: '>= 0.4'} + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -571,10 +583,87 @@ packages: path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + + pg-connection-string@2.7.0: + resolution: {integrity: sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.7.0: + resolution: {integrity: sha512-ZOBQForurqh4zZWjrgSwwAtzJ7QiRX0ovFkZr2klsen3Nm0aoh33Ls0fzfv3imeH/nw/O27cjdz5kzYJfeGp/g==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.7.0: + resolution: {integrity: sha512-hTK/mE36i8fDDhgDFjy6xNOG+LCorxLG3WO17tku+ij6sVHXh1jQUJ8hYAnRhNla4QVD2H8er/FOjc/+EgC6yQ==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg-types@4.0.2: + resolution: {integrity: sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng==} + engines: {node: '>=10'} + + pg@8.13.1: + resolution: {integrity: sha512-OUir1A0rPNZlX//c7ksiu7crsGZTKSOXJPgtNiHGIlC9H0lO+NC6ZDYksSgBYY/thSWhnSRBv8w1lieNNGATNQ==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-date@2.1.0: + resolution: {integrity: sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==} + engines: {node: '>=12'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.4: + resolution: {integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -664,6 +753,10 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -755,6 +848,10 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -886,6 +983,12 @@ snapshots: dependencies: undici-types: 6.20.0 + '@types/pg@8.11.10': + dependencies: + '@types/node': 22.10.2 + pg-protocol: 1.7.0 + pg-types: 4.0.2 + '@types/qs@6.9.17': {} '@types/range-parser@1.2.7': {} @@ -1282,6 +1385,8 @@ snapshots: object-inspect@1.13.3: {} + obuf@1.1.2: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -1290,8 +1395,77 @@ snapshots: path-to-regexp@0.1.12: {} + pg-cloudflare@1.1.1: + optional: true + + pg-connection-string@2.7.0: {} + + pg-int8@1.0.1: {} + + pg-numeric@1.0.2: {} + + pg-pool@3.7.0(pg@8.13.1): + dependencies: + pg: 8.13.1 + + pg-protocol@1.7.0: {} + + pg-types@2.2.0: + dependencies: + pg-int8: 1.0.1 + postgres-array: 2.0.0 + postgres-bytea: 1.0.0 + postgres-date: 1.0.7 + postgres-interval: 1.2.0 + + pg-types@4.0.2: + dependencies: + pg-int8: 1.0.1 + pg-numeric: 1.0.2 + postgres-array: 3.0.2 + postgres-bytea: 3.0.0 + postgres-date: 2.1.0 + postgres-interval: 3.0.0 + postgres-range: 1.1.4 + + pg@8.13.1: + dependencies: + pg-connection-string: 2.7.0 + pg-pool: 3.7.0(pg@8.13.1) + pg-protocol: 1.7.0 + pg-types: 2.2.0 + pgpass: 1.0.5 + optionalDependencies: + pg-cloudflare: 1.1.1 + + pgpass@1.0.5: + dependencies: + split2: 4.2.0 + picomatch@2.3.1: {} + postgres-array@2.0.0: {} + + postgres-array@3.0.2: {} + + postgres-bytea@1.0.0: {} + + postgres-bytea@3.0.0: + dependencies: + obuf: 1.1.2 + + postgres-date@1.0.7: {} + + postgres-date@2.1.0: {} + + postgres-interval@1.2.0: + dependencies: + xtend: 4.0.2 + + postgres-interval@3.0.0: {} + + postgres-range@1.1.4: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -1403,6 +1577,8 @@ snapshots: source-map-js@1.2.1: {} + split2@4.2.0: {} + statuses@2.0.1: {} string-width@4.2.3: @@ -1482,6 +1658,8 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 + xtend@4.0.2: {} + y18n@5.0.8: {} yargs-parser@21.1.1: {} diff --git a/nodeJS/Learning/06/public/js/index.js b/nodeJS/Learning/06/public/js/index.js new file mode 100644 index 0000000..e69de29 diff --git a/nodeJS/Learning/06/src/database/pg.ts b/nodeJS/Learning/06/src/database/pg.ts new file mode 100644 index 0000000..963227a --- /dev/null +++ b/nodeJS/Learning/06/src/database/pg.ts @@ -0,0 +1,14 @@ +import { Pool } from "pg"; + +console.log(process.env.DB_HOST); + +const pg = new Pool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + port: parseInt(process.env.DB_PORT as string), +}); + +// export pg to outside to use +export default pg; \ No newline at end of file diff --git a/nodeJS/Learning/06/src/index.ts b/nodeJS/Learning/06/src/index.ts index 875a5c1..97680b4 100644 --- a/nodeJS/Learning/06/src/index.ts +++ b/nodeJS/Learning/06/src/index.ts @@ -1,10 +1,17 @@ -import express, { Application, Request, Response } from "express"; import dotenv from "dotenv"; -dotenv.config({ path: "$(__dirname)/../env" }); +dotenv.config({ path: ".env" }); + +import express, { Application, Request, Response } from "express"; +import pg from "./database/pg"; +import { PoolClient } from "pg"; const app: Application = express(); const port: number = parseInt(process.env.PORT as string) || 3000; +//Middleware +app.use(express.json()); +app.use(express.urlencoded({ extended: true })); + //Setting up for EJS app.set("views", `./src/views`); app.set("view engine", "ejs"); @@ -14,14 +21,82 @@ app.use(express.static(`${__dirname}/../public`)); //check and send index ejs app.get("/", (_req: Request, res: Response): void => { - const date = new Date().toLocaleString(); + let todos: string[] = []; - res.render("index", { - time: date, + //Query postgres database to get all todos (async await) + pg.query("SELECT * FROM todos", async (err: Error, result: any) => { + if (err) { + console.log("Error querying todos", err); + return; + } + + todos = result.rows.map((row: any) => row.todo); + } + + res.render("index",{ + todos, }); }); +app.post("/form-action", (req: Request, res: Response): void => { + const todo: string = req.body.todo; + + //query postgres to insert todo, $1 is a placeholder for the value of todo + pg.query("INSERT INTO todos (todo) VALUES ($1)", [todo], (err: Error) => { + if (err) { + console.log("Error inserting todo", err); + return; + } + + console.log(`Inserted ${todo} successfully`); + }); + + res.redirect("/"); +}); + +// app.delete("/delete-todo/:todo", (req: Request, res: Response): void => { +// //delete todo from postgres +// }); + app.listen(port, (): void => { console.log(`Server is running on port ${port}`); }); +//Connect to postgres, postgres initialization +pg.connect( + (err: Error | undefined, client: PoolClient | undefined, done): void => { + if (err) { + console.log("Error connecting to pg", err); + return; + } + if (!client) { + console.log("No client found"); + return; + } + + // Attempt to Query (asking the database, to check it is connected), it might take us a while and we wont be able to run the rest of the program + // Async this + client.query("SELECT NOW()", async (err: Error, _result: any) => { + if (err) { + console.log("Error querying pg", err); + return; + } + + //Create the table if no error (await) + //Query statement, instruction "CREATE TABLE IF NOT EXISTS todos", there is a whole table, https://www.w3schools.com/sql/default.asp + //VACHAR is a string, 255 is the max length of the string + await client.query( + `CREATE TABLE IF NOT EXISTS todos ( + todo VARCHAR(255) NOT NULL + )`, + (err: Error) => { + console.log("Error creating table", err); + return; + } + ); + + console.log("Connected to postgres successfully"); + done(); + }); + } +); diff --git a/nodeJS/Learning/06/src/views/index.ejs b/nodeJS/Learning/06/src/views/index.ejs index 1d0e534..8418a94 100644 --- a/nodeJS/Learning/06/src/views/index.ejs +++ b/nodeJS/Learning/06/src/views/index.ejs @@ -33,7 +33,13 @@

Add something cute to my to-do list!

- +
@@ -44,6 +50,9 @@

To do list

    + + +