├── .gitignore
├── bun-and-hono
├── bun-hono-task-crud-api
│ ├── .gitignore
│ ├── README.md
│ ├── bun.lock
│ ├── bun_hono_task_crud.sqlite
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── controllers
│ │ │ ├── auth.ts
│ │ │ └── task.ts
│ │ ├── database
│ │ │ └── db.ts
│ │ ├── index.ts
│ │ └── types
│ │ │ └── index.ts
│ └── tsconfig.json
└── concepts
│ ├── .gitignore
│ ├── README.md
│ ├── bun.lock
│ ├── bundb.sqlite
│ ├── features
│ ├── binary.ts
│ ├── fetch.ts
│ ├── fs.ts
│ ├── hashing.ts
│ ├── meta-env.ts
│ ├── server.ts
│ └── sqllite.ts
│ ├── index.ts
│ ├── output.txt
│ ├── package.json
│ ├── read.txt
│ └── tsconfig.json
├── nest-js
├── concepts
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── blog
│ │ │ ├── blog.controller.spec.ts
│ │ │ ├── blog.controller.ts
│ │ │ ├── blog.module.ts
│ │ │ ├── blog.service.spec.ts
│ │ │ └── blog.service.ts
│ │ └── main.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
├── file-upload
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prisma
│ │ ├── migrations
│ │ │ ├── 20250302190131_init
│ │ │ │ └── migration.sql
│ │ │ └── migration_lock.toml
│ │ └── schema.prisma
│ ├── src
│ │ ├── app.controller.spec.ts
│ │ ├── app.controller.ts
│ │ ├── app.module.ts
│ │ ├── app.service.ts
│ │ ├── file-upload
│ │ │ ├── file-upload.controller.spec.ts
│ │ │ ├── file-upload.controller.ts
│ │ │ ├── file-upload.module.ts
│ │ │ ├── file-upload.service.spec.ts
│ │ │ └── file-upload.service.ts
│ │ ├── main.ts
│ │ └── prisma
│ │ │ └── prisma.service.ts
│ ├── test
│ │ ├── app.e2e-spec.ts
│ │ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── travel-tracker
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── eslint.config.mjs
│ ├── nest-cli.json
│ ├── package-lock.json
│ ├── package.json
│ ├── prisma
│ ├── migrations
│ │ ├── 20250301182602_init
│ │ │ └── migration.sql
│ │ └── migration_lock.toml
│ └── schema.prisma
│ ├── src
│ ├── app.controller.spec.ts
│ ├── app.controller.ts
│ ├── app.module.ts
│ ├── app.service.ts
│ ├── auth
│ │ ├── auth.controller.spec.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.spec.ts
│ │ ├── auth.service.ts
│ │ ├── dto
│ │ │ ├── login.dto.ts
│ │ │ └── register.dto.ts
│ │ ├── jwt-auth.guard.ts
│ │ └── jwt.strategy.ts
│ ├── destinations
│ │ ├── destinations.controller.spec.ts
│ │ ├── destinations.controller.ts
│ │ ├── destinations.module.ts
│ │ ├── destinations.service.spec.ts
│ │ ├── destinations.service.ts
│ │ └── dto
│ │ │ ├── create-destination.dto.ts
│ │ │ └── update-destination.dto.ts
│ ├── main.ts
│ └── prisma
│ │ ├── prisma.module.ts
│ │ ├── prisma.service.spec.ts
│ │ └── prisma.service.ts
│ ├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
│ ├── tsconfig.build.json
│ └── tsconfig.json
└── postgres
├── postgres-with-prisma
├── .dockerignore
├── .gitignore
├── Dockerfile
├── docker-compose.yml
├── package-lock.json
├── package.json
├── prisma
│ ├── migrations
│ │ ├── 20250223203943_init
│ │ │ └── migration.sql
│ │ ├── 20250223205502_author
│ │ │ └── migration.sql
│ │ ├── 20250223214459_delete
│ │ │ └── migration.sql
│ │ └── migration_lock.toml
│ └── schema.prisma
├── prometheus.yml
└── src
│ ├── controllers
│ ├── authorController.js
│ └── bookController.js
│ ├── routes
│ ├── authorRoutes.js
│ └── bookRoutes.js
│ ├── server.js
│ └── services
│ ├── authorService.js
│ └── bookService.js
└── postgress-concepts
├── package-lock.json
├── package.json
└── src
├── concepts
├── aggregation.js
├── basic-queries.js
├── filtering-sorting.js
├── joins.js
└── relationships.js
├── db
└── db.js
└── main.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .env
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/.gitignore:
--------------------------------------------------------------------------------
1 | # deps
2 | node_modules/
3 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/README.md:
--------------------------------------------------------------------------------
1 | To install dependencies:
2 | ```sh
3 | bun install
4 | ```
5 |
6 | To run:
7 | ```sh
8 | bun run dev
9 | ```
10 |
11 | open http://localhost:3000
12 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/bun.lock:
--------------------------------------------------------------------------------
1 | {
2 | "lockfileVersion": 1,
3 | "workspaces": {
4 | "": {
5 | "name": "bun-hono-task-crud-api",
6 | "dependencies": {
7 | "hono": "^4.7.2",
8 | },
9 | "devDependencies": {
10 | "@types/bun": "latest",
11 | },
12 | },
13 | },
14 | "packages": {
15 | "@types/bun": ["@types/bun@1.2.2", "", { "dependencies": { "bun-types": "1.2.2" } }, "sha512-tr74gdku+AEDN5ergNiBnplr7hpDp3V1h7fqI2GcR/rsUaM39jpSeKH0TFibRvU0KwniRx5POgaYnaXbk0hU+w=="],
16 |
17 | "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="],
18 |
19 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
20 |
21 | "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
22 |
23 | "hono": ["hono@4.7.2", "", {}, "sha512-8V5XxoOF6SI12jkHkzX/6aLBMU5GEF5g387EjVSQipS0DlxWgWGSMeEayY3CRBjtTUQYwLHx9JYouWqKzy2Vng=="],
24 |
25 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/bun_hono_task_crud.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/nodejs-full-course-part-3/d96ce13d2a46197a843d28fadd4ec6ec5aa6ff0c/bun-and-hono/bun-hono-task-crud-api/bun_hono_task_crud.sqlite
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bun-hono-task-crud-api",
3 | "lockfileVersion": 3,
4 | "requires": true,
5 | "packages": {
6 | "": {
7 | "name": "bun-hono-task-crud-api",
8 | "dependencies": {
9 | "@hono/zod-validator": "^0.4.3",
10 | "hono": "^4.7.2"
11 | },
12 | "devDependencies": {
13 | "@types/bun": "latest"
14 | }
15 | },
16 | "node_modules/@hono/zod-validator": {
17 | "version": "0.4.3",
18 | "resolved": "https://registry.npmjs.org/@hono/zod-validator/-/zod-validator-0.4.3.tgz",
19 | "integrity": "sha512-xIgMYXDyJ4Hj6ekm9T9Y27s080Nl9NXHcJkOvkXPhubOLj8hZkOL8pDnnXfvCf5xEE8Q4oMFenQUZZREUY2gqQ==",
20 | "peerDependencies": {
21 | "hono": ">=3.9.0",
22 | "zod": "^3.19.1"
23 | }
24 | },
25 | "node_modules/@types/bun": {
26 | "version": "1.2.2",
27 | "resolved": "https://registry.npmjs.org/@types/bun/-/bun-1.2.2.tgz",
28 | "integrity": "sha512-tr74gdku+AEDN5ergNiBnplr7hpDp3V1h7fqI2GcR/rsUaM39jpSeKH0TFibRvU0KwniRx5POgaYnaXbk0hU+w==",
29 | "dev": true,
30 | "dependencies": {
31 | "bun-types": "1.2.2"
32 | }
33 | },
34 | "node_modules/@types/node": {
35 | "version": "22.13.4",
36 | "dev": true,
37 | "license": "MIT",
38 | "dependencies": {
39 | "undici-types": "~6.20.0"
40 | }
41 | },
42 | "node_modules/@types/ws": {
43 | "version": "8.5.14",
44 | "dev": true,
45 | "license": "MIT",
46 | "dependencies": {
47 | "@types/node": "*"
48 | }
49 | },
50 | "node_modules/bun-types": {
51 | "version": "1.2.2",
52 | "dev": true,
53 | "license": "MIT",
54 | "dependencies": {
55 | "@types/node": "*",
56 | "@types/ws": "~8.5.10"
57 | }
58 | },
59 | "node_modules/hono": {
60 | "version": "4.7.2",
61 | "license": "MIT",
62 | "engines": {
63 | "node": ">=16.9.0"
64 | }
65 | },
66 | "node_modules/undici-types": {
67 | "version": "6.20.0",
68 | "dev": true,
69 | "license": "MIT"
70 | },
71 | "node_modules/zod": {
72 | "version": "3.24.2",
73 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz",
74 | "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==",
75 | "peer": true,
76 | "funding": {
77 | "url": "https://github.com/sponsors/colinhacks"
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bun-hono-task-crud-api",
3 | "scripts": {
4 | "dev": "bun run --hot src/index.ts"
5 | },
6 | "dependencies": {
7 | "@hono/zod-validator": "^0.4.3",
8 | "hono": "^4.7.2"
9 | },
10 | "devDependencies": {
11 | "@types/bun": "latest"
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/src/controllers/auth.ts:
--------------------------------------------------------------------------------
1 | import type { Context } from "hono";
2 | import { Database } from "bun:sqlite";
3 | import { User } from "../types";
4 | import { password as bunPassword } from "bun";
5 | import { sign } from "hono/jwt";
6 |
7 | export async function registerUser(c: Context, db: Database) {
8 | const { username, password, role = "user" } = await c.req.json();
9 |
10 | if (!username || !password) {
11 | return c.json(
12 | {
13 | error: "Username and password are required",
14 | },
15 | 400
16 | );
17 | }
18 |
19 | if (role !== "user" && role !== "admin") {
20 | return c.json({ error: "Invalid role" }, 400);
21 | }
22 |
23 | try {
24 | const existingUser = db
25 | .query("SELECT * FROM users WHERE username = ?")
26 | .get(username) as User | undefined;
27 |
28 | if (existingUser) {
29 | return c.json(
30 | {
31 | error:
32 | "User is already exists with same username! Please try with a diff username",
33 | },
34 | 400
35 | );
36 | }
37 |
38 | //hashing the password
39 | const hashedPassword = await bunPassword.hash(password);
40 |
41 | db.run("INSERT INTO users (username, password, role) VALUES (?,?,?)", [
42 | username,
43 | hashedPassword,
44 | role,
45 | ]);
46 |
47 | return c.json(
48 | {
49 | message: "User registered successfully!",
50 | },
51 | 201
52 | );
53 | } catch (e) {
54 | console.error(e);
55 | return c.json({ error: "Internal server error" }, 500);
56 | }
57 | }
58 |
59 | export async function loginUser(c: Context, db: Database) {
60 | const { username, password } = await c.req.json();
61 | if (!username || !password) {
62 | return c.json(
63 | {
64 | error: "Username and password are required",
65 | },
66 | 400
67 | );
68 | }
69 |
70 | try {
71 | const user = db
72 | .query("SELECT * FROM users WHERE username = ?")
73 | .get(username) as User | undefined;
74 | if (!user) {
75 | return c.json(
76 | {
77 | error: "Invalid credentials",
78 | },
79 | 401
80 | );
81 | }
82 |
83 | //verify the password user entered
84 | const isPasswordValid = await bunPassword.verify(password, user.password);
85 | if (!isPasswordValid) {
86 | return c.json(
87 | {
88 | error: "Invalid password",
89 | },
90 | 401
91 | );
92 | }
93 |
94 | const token = await sign(
95 | {
96 | userId: user.id,
97 | role: user.role,
98 | },
99 | process.env.JWT_SECRET || "JWT_SECRET"
100 | );
101 |
102 | return c.json({ token });
103 | } catch (error) {
104 | console.error(error);
105 | return c.json({ error: "Internal server error" }, 500);
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/src/controllers/task.ts:
--------------------------------------------------------------------------------
1 | import type { Context } from "hono";
2 | import { Database } from "bun:sqlite";
3 | import { Task } from "../types";
4 |
5 | export async function createTask(c: Context, db: Database) {
6 | const userId = c.get("jwtPayload").userId;
7 | const userRole = c.get("jwtPayload").role;
8 | const { title, description, user_id } = await c.req.json();
9 |
10 | if (!userId) {
11 | return c.json(
12 | {
13 | error: "Unauthenticated! You need to login to create task",
14 | },
15 | 401
16 | );
17 | }
18 |
19 | if (userRole !== "admin") {
20 | return c.json(
21 | {
22 | error: "Unauthorized! Only admin users can create a post",
23 | },
24 | 403
25 | );
26 | }
27 |
28 | if (userId !== user_id) {
29 | return c.json(
30 | {
31 | error: "Invalid user with diff user id",
32 | },
33 | 403
34 | );
35 | }
36 |
37 | try {
38 | const result = db
39 | .query(
40 | `
41 | INSERT INTO tasks (user_id, title, description) VALUES (?,?,?) RETURNING *
42 | `
43 | )
44 | .get(user_id, title, description) as Task;
45 |
46 | return c.json(result, 201);
47 | } catch (error) {
48 | console.error(error);
49 | return c.json({ error: "Internal server error" }, 500);
50 | }
51 | }
52 |
53 | export async function getAllTasks(c: Context, db: Database) {
54 | try {
55 | const extractAllTasks = db.query("SELECT * FROM tasks").all() as Task[];
56 | return c.json(extractAllTasks, 200);
57 | } catch (error) {
58 | console.error(error);
59 | return c.json({ error: "Internal server error" }, 500);
60 | }
61 | }
62 |
63 | export async function getTask(c: Context, db: Database) {
64 | const taskId = c.req.param("id");
65 |
66 | try {
67 | const extractSingleTask = db
68 | .query("SELECT * FROM tasks WHERE id =?")
69 | .get(taskId) as Task | undefined;
70 |
71 | if (!extractSingleTask) {
72 | return c.json(
73 | {
74 | error: "Task not found! Please try again",
75 | },
76 | 404
77 | );
78 | }
79 |
80 | return c.json(extractSingleTask, 200);
81 | } catch (error) {
82 | console.error(error);
83 | return c.json({ error: "Internal server error" }, 500);
84 | }
85 | }
86 |
87 | export async function updateATask(c: Context, db: Database) {
88 | const userId = c.get("jwtPayload").userId;
89 | const userRole = c.get("jwtPayload").role;
90 | const taskId = c.req.param("id");
91 | const { title, description, user_id } = await c.req.json();
92 |
93 | if (!userId) {
94 | return c.json(
95 | {
96 | error: "Unauthenticated! You need to login to create task",
97 | },
98 | 401
99 | );
100 | }
101 |
102 | if (userRole !== "admin") {
103 | return c.json(
104 | {
105 | error: "Unauthorized! Only admin users can update a post",
106 | },
107 | 403
108 | );
109 | }
110 |
111 | if (userId !== user_id) {
112 | return c.json(
113 | {
114 | error: "You are not owner of this post, you can't update this!",
115 | },
116 | 403
117 | );
118 | }
119 |
120 | try {
121 | const extractSingleTask = db
122 | .query("SELECT * FROM tasks WHERE id= ?")
123 | .get(taskId) as Task | undefined;
124 |
125 | if (!extractSingleTask) {
126 | return c.json(
127 | {
128 | error: "Task not found! Please try again",
129 | },
130 | 404
131 | );
132 | }
133 |
134 | const updatedTask = db
135 | .query(
136 | `
137 | UPDATE tasks
138 | SET title = ?, description = ?, user_id = ?
139 | WHERE id = ?
140 | RETURNING *
141 | `
142 | )
143 | .get(
144 | title || extractSingleTask.title,
145 | description !== undefined ? description : extractSingleTask.description,
146 | user_id || extractSingleTask.user_id,
147 | taskId
148 | ) as Task;
149 |
150 | return c.json(updatedTask, 200);
151 | } catch (error) {
152 | console.error(error);
153 | return c.json({ error: "Internal server error" }, 500);
154 | }
155 | }
156 |
157 | export async function deleteTask(c: Context, db: Database) {
158 | const userId = c.get("jwtPayload").userId;
159 | const userRole = c.get("jwtPayload").role;
160 | const taskId = c.req.param("id");
161 | const { user_id } = await c.req.json();
162 |
163 | if (!userId) {
164 | return c.json(
165 | {
166 | error: "Unauthenticated! You need to login to create task",
167 | },
168 | 401
169 | );
170 | }
171 |
172 | if (userRole !== "admin") {
173 | return c.json(
174 | {
175 | error: "Unauthorized! Only admin users can delete a post",
176 | },
177 | 403
178 | );
179 | }
180 |
181 | if (userId !== user_id) {
182 | return c.json(
183 | {
184 | error: "You are not owner of this post, you can't delete this!",
185 | },
186 | 403
187 | );
188 | }
189 |
190 | try {
191 | const deletedTask = db.query("DELETE FROM tasks WHERE id= ?").run(taskId);
192 |
193 | if (deletedTask.changes === 0) {
194 | return c.json(
195 | {
196 | error: "Task not found! Please try again",
197 | },
198 | 404
199 | );
200 | }
201 |
202 | return c.json({ message: "Task deleted successfully!" });
203 | } catch (error) {
204 | console.error(error);
205 | return c.json({ error: "Internal server error" }, 500);
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/src/database/db.ts:
--------------------------------------------------------------------------------
1 | import { Database } from "bun:sqlite";
2 |
3 | export function initDatabase(): Database {
4 | const db = new Database("bun_hono_task_crud.sqlite");
5 |
6 | //users table
7 | db.run(`
8 | CREATE TABLE IF NOT EXISTS users (
9 | id INTEGER PRIMARY KEY AUTOINCREMENT,
10 | username TEXT UNIQUE NOT NULL,
11 | password TEXT NOT NULL,
12 | role TEXT CHECK(role IN ('user', 'admin')) NOT NULL DEFAULT 'user'
13 | )
14 | `);
15 |
16 | //tasks table
17 | db.run(`
18 | CREATE TABLE IF NOT EXISTS tasks (
19 | id INTEGER PRIMARY KEY AUTOINCREMENT,
20 | user_id INTEGER NOT NULL,
21 | title TEXT NOT NULL,
22 | description TEXT,
23 | created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
24 | FOREIGN KEY (user_id) REFERENCES users(id)
25 |
26 | )
27 | `);
28 |
29 | return db;
30 | }
31 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/src/index.ts:
--------------------------------------------------------------------------------
1 | import { Hono } from "hono";
2 | import { initDatabase } from "./database/db";
3 | import { cors } from "hono/cors";
4 | import { logger } from "hono/logger";
5 | import { z } from "zod";
6 | import { zValidator } from "@hono/zod-validator";
7 | import { loginUser, registerUser } from "./controllers/auth";
8 | import { jwt } from "hono/jwt";
9 | import {
10 | createTask,
11 | deleteTask,
12 | getAllTasks,
13 | getTask,
14 | updateATask,
15 | } from "./controllers/task";
16 |
17 | const app = new Hono();
18 | const db = initDatabase();
19 |
20 | app.use("*", cors());
21 | app.use("*", logger());
22 |
23 | const auth = jwt({
24 | secret: process.env.JWT_SECRET || "JWT_SECRET",
25 | });
26 |
27 | //Input validation
28 | const registerSchema = z.object({
29 | username: z.string().min(3).max(25),
30 | password: z.string().min(5),
31 | role: z.enum(["user", "admin"]).optional(),
32 | });
33 |
34 | const loginSchema = z.object({
35 | username: z.string(),
36 | password: z.string(),
37 | });
38 |
39 | const taskSchema = z.object({
40 | title: z.string().min(1).max(100),
41 | description: z.string().optional(),
42 | user_id: z.number().int().positive(),
43 | });
44 |
45 | //auth related routes
46 | app.post("/register-user", zValidator("json", registerSchema), (c) =>
47 | registerUser(c, db)
48 | );
49 | app.post("/login", zValidator("json", loginSchema), (c) => loginUser(c, db));
50 |
51 | //task routes
52 | app.post("/tasks", auth, zValidator("json", taskSchema), (c) =>
53 | createTask(c, db)
54 | );
55 | app.get("/tasks", auth, (c) => getAllTasks(c, db));
56 | app.get("/tasks/:id", auth, (c) => getTask(c, db));
57 | app.put("/tasks/:id", auth, zValidator("json", taskSchema), (c) =>
58 | updateATask(c, db)
59 | );
60 |
61 | app.delete("/tasks/:id", auth, (c) => deleteTask(c, db));
62 |
63 | app.get("/", (c) => {
64 | return c.text("Hello, User & Task management using Bun & Hono");
65 | });
66 |
67 | app.get("/db-test", (c) => {
68 | const result = db.query("SELECT sqlite_version()").get();
69 |
70 | return c.json({
71 | message: "Database connected successfully",
72 | sqlite_version: result,
73 | });
74 | });
75 |
76 | export default app;
77 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/src/types/index.ts:
--------------------------------------------------------------------------------
1 | export type User = {
2 | id: number;
3 | username: string;
4 | password: string;
5 | role: "user" | "admin";
6 | };
7 |
8 | export type Task = {
9 | id: number;
10 | user_id: number;
11 | title: string;
12 | description: string;
13 | created_at: string;
14 | };
15 |
--------------------------------------------------------------------------------
/bun-and-hono/bun-hono-task-crud-api/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "jsx": "react-jsx",
5 | "jsxImportSource": "hono/jsx"
6 | }
7 | }
--------------------------------------------------------------------------------
/bun-and-hono/concepts/.gitignore:
--------------------------------------------------------------------------------
1 | # Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
2 |
3 | # Logs
4 |
5 | logs
6 | _.log
7 | npm-debug.log_
8 | yarn-debug.log*
9 | yarn-error.log*
10 | lerna-debug.log*
11 | .pnpm-debug.log*
12 |
13 | # Caches
14 |
15 | .cache
16 |
17 | # Diagnostic reports (https://nodejs.org/api/report.html)
18 |
19 | report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
20 |
21 | # Runtime data
22 |
23 | pids
24 | _.pid
25 | _.seed
26 | *.pid.lock
27 |
28 | # Directory for instrumented libs generated by jscoverage/JSCover
29 |
30 | lib-cov
31 |
32 | # Coverage directory used by tools like istanbul
33 |
34 | coverage
35 | *.lcov
36 |
37 | # nyc test coverage
38 |
39 | .nyc_output
40 |
41 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
42 |
43 | .grunt
44 |
45 | # Bower dependency directory (https://bower.io/)
46 |
47 | bower_components
48 |
49 | # node-waf configuration
50 |
51 | .lock-wscript
52 |
53 | # Compiled binary addons (https://nodejs.org/api/addons.html)
54 |
55 | build/Release
56 |
57 | # Dependency directories
58 |
59 | node_modules/
60 | jspm_packages/
61 |
62 | # Snowpack dependency directory (https://snowpack.dev/)
63 |
64 | web_modules/
65 |
66 | # TypeScript cache
67 |
68 | *.tsbuildinfo
69 |
70 | # Optional npm cache directory
71 |
72 | .npm
73 |
74 | # Optional eslint cache
75 |
76 | .eslintcache
77 |
78 | # Optional stylelint cache
79 |
80 | .stylelintcache
81 |
82 | # Microbundle cache
83 |
84 | .rpt2_cache/
85 | .rts2_cache_cjs/
86 | .rts2_cache_es/
87 | .rts2_cache_umd/
88 |
89 | # Optional REPL history
90 |
91 | .node_repl_history
92 |
93 | # Output of 'npm pack'
94 |
95 | *.tgz
96 |
97 | # Yarn Integrity file
98 |
99 | .yarn-integrity
100 |
101 | # dotenv environment variable files
102 |
103 | .env
104 | .env.development.local
105 | .env.test.local
106 | .env.production.local
107 | .env.local
108 |
109 | # parcel-bundler cache (https://parceljs.org/)
110 |
111 | .parcel-cache
112 |
113 | # Next.js build output
114 |
115 | .next
116 | out
117 |
118 | # Nuxt.js build / generate output
119 |
120 | .nuxt
121 | dist
122 |
123 | # Gatsby files
124 |
125 | # Comment in the public line in if your project uses Gatsby and not Next.js
126 |
127 | # https://nextjs.org/blog/next-9-1#public-directory-support
128 |
129 | # public
130 |
131 | # vuepress build output
132 |
133 | .vuepress/dist
134 |
135 | # vuepress v2.x temp and cache directory
136 |
137 | .temp
138 |
139 | # Docusaurus cache and generated files
140 |
141 | .docusaurus
142 |
143 | # Serverless directories
144 |
145 | .serverless/
146 |
147 | # FuseBox cache
148 |
149 | .fusebox/
150 |
151 | # DynamoDB Local files
152 |
153 | .dynamodb/
154 |
155 | # TernJS port file
156 |
157 | .tern-port
158 |
159 | # Stores VSCode versions used for testing VSCode extensions
160 |
161 | .vscode-test
162 |
163 | # yarn v2
164 |
165 | .yarn/cache
166 | .yarn/unplugged
167 | .yarn/build-state.yml
168 | .yarn/install-state.gz
169 | .pnp.*
170 |
171 | # IntelliJ based IDEs
172 | .idea
173 |
174 | # Finder (MacOS) folder config
175 | .DS_Store
176 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/README.md:
--------------------------------------------------------------------------------
1 | # concepts
2 |
3 | To install dependencies:
4 |
5 | ```bash
6 | bun install
7 | ```
8 |
9 | To run:
10 |
11 | ```bash
12 | bun run index.ts
13 | ```
14 |
15 | This project was created using `bun init` in bun v1.2.2. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
16 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/bun.lock:
--------------------------------------------------------------------------------
1 | {
2 | "lockfileVersion": 1,
3 | "workspaces": {
4 | "": {
5 | "name": "concepts",
6 | "devDependencies": {
7 | "@types/bun": "latest",
8 | },
9 | "peerDependencies": {
10 | "typescript": "^5.0.0",
11 | },
12 | },
13 | },
14 | "packages": {
15 | "@types/bun": ["@types/bun@1.2.2", "", { "dependencies": { "bun-types": "1.2.2" } }, "sha512-tr74gdku+AEDN5ergNiBnplr7hpDp3V1h7fqI2GcR/rsUaM39jpSeKH0TFibRvU0KwniRx5POgaYnaXbk0hU+w=="],
16 |
17 | "@types/node": ["@types/node@22.13.4", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ywP2X0DYtX3y08eFVx5fNIw7/uIv8hYUKgXoK8oayJlLnKcRfEYCxWMVE1XagUdVtCJlZT1AU4LXEABW+L1Peg=="],
18 |
19 | "@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
20 |
21 | "bun-types": ["bun-types@1.2.2", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-RCbMH5elr9gjgDGDhkTTugA21XtJAy/9jkKe/G3WR2q17VPGhcquf9Sir6uay9iW+7P/BV0CAHA1XlHXMAVKHg=="],
22 |
23 | "typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
24 |
25 | "undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/bundb.sqlite:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/sangammukherjee/nodejs-full-course-part-3/d96ce13d2a46197a843d28fadd4ec6ec5aa6ff0c/bun-and-hono/concepts/bundb.sqlite
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/binary.ts:
--------------------------------------------------------------------------------
1 | function binaryDataOperations() {
2 | const buf = new ArrayBuffer(8);
3 | console.log("Arraybuffer size", buf.byteLength);
4 |
5 | const dv = new DataView(buf);
6 | dv.setUint8(0, 3);
7 | dv.setUint16(1, 513);
8 |
9 | console.log(dv.getUint8(0));
10 | console.log(dv.getUint16(1));
11 |
12 | const unint8Array = new Uint8Array([0, 1, 2, 3, 4]);
13 | console.log(unint8Array);
14 |
15 | const nodeBuffer = Buffer.from("Hello Bun Js");
16 | console.log(nodeBuffer, nodeBuffer.toString());
17 |
18 | const blob = new Blob(["Hello"], { type: "text/html" });
19 | console.log(blob.size, blob.type);
20 |
21 | const encoder = new TextEncoder();
22 | const encodedVal = encoder.encode("Hello Bun!");
23 | console.log(encodedVal, "encodedVal");
24 |
25 | const decoder = new TextDecoder();
26 | console.log(decoder.decode(encodedVal));
27 | }
28 |
29 | binaryDataOperations();
30 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/fetch.ts:
--------------------------------------------------------------------------------
1 | async function fetchDemo() {
2 | const response = await fetch("https://dummyjson.com/products/1");
3 | const data = await response.json();
4 | console.log(data);
5 | }
6 |
7 | fetchDemo();
8 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/fs.ts:
--------------------------------------------------------------------------------
1 | import type { BunFile } from "bun";
2 |
3 | async function fileSystemOperations() {
4 | //Read a file
5 | const file: BunFile = Bun.file("read.txt");
6 | console.log(file.size);
7 | console.log(file.type, "type");
8 | const extractTextContent = await file.text();
9 | console.log(extractTextContent);
10 | const arrayBuffer = await file.arrayBuffer();
11 | const unint8Array = await file.bytes();
12 |
13 | console.log(arrayBuffer, unint8Array);
14 |
15 | const content = "Hello! I am learning Bun for the first time";
16 | await Bun.write("output.txt", content);
17 | console.log("file created successfully");
18 |
19 | const inputFile = Bun.file("read.txt");
20 | await Bun.write("read_copy.txt", inputFile);
21 | console.log("file copied and created successfully");
22 |
23 | const isFileExists = await Bun.file("read_copy.txt").exists();
24 | console.log(isFileExists);
25 |
26 | await Bun.file("read_copy.txt").delete();
27 | console.log("Read copy file is deleted successfully!!");
28 | }
29 |
30 | fileSystemOperations();
31 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/hashing.ts:
--------------------------------------------------------------------------------
1 | async function hashingOperations() {
2 | const password = "123456";
3 | const hash = await Bun.password.hash(password);
4 | console.log(hash);
5 |
6 | const isMatch = await Bun.password.verify(password, hash);
7 |
8 | console.log(isMatch);
9 |
10 | const argonHashExample = await Bun.password.hash(password, {
11 | algorithm: "argon2id",
12 | memoryCost: 4,
13 | timeCost: 3,
14 | });
15 |
16 | console.log(argonHashExample);
17 |
18 | const bcryptHashExample = await Bun.password.hash(password, {
19 | algorithm: "bcrypt",
20 | cost: 10,
21 | });
22 |
23 | console.log(bcryptHashExample);
24 | }
25 |
26 | hashingOperations();
27 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/meta-env.ts:
--------------------------------------------------------------------------------
1 | function importMetaAndEnv() {
2 | console.log(import.meta.url);
3 |
4 | console.log("Is this main module ?", import.meta.main);
5 | console.log(process.env.NODE_ENV);
6 | console.log(Bun.env.NODE_ENV);
7 | }
8 |
9 | importMetaAndEnv();
10 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/server.ts:
--------------------------------------------------------------------------------
1 | import type { Server } from "bun";
2 |
3 | interface User {
4 | id: number;
5 | name: string;
6 | }
7 |
8 | interface ApiResponse {
9 | message: string;
10 | method: string;
11 | route: string;
12 | data?: User | User[];
13 | }
14 |
15 | const users: User[] = [
16 | {
17 | id: 1,
18 | name: "John",
19 | },
20 | {
21 | id: 2,
22 | name: "raj",
23 | },
24 | {
25 | id: 3,
26 | name: "Sangam",
27 | },
28 | {
29 | id: 4,
30 | name: "John4",
31 | },
32 | {
33 | id: 5,
34 | name: "John5",
35 | },
36 | ];
37 |
38 | const server: Server = Bun.serve({
39 | port: 3000,
40 | fetch(req: Request): Response {
41 | const url = new URL(req.url);
42 | const method = req.method;
43 |
44 | let response: ApiResponse = {
45 | message: "Hello from Bun server!",
46 | method: method,
47 | route: url.pathname,
48 | };
49 |
50 | if (url.pathname === "/") {
51 | //root route
52 | if (method === "GET") {
53 | response.message = "Welcome to Bun API!";
54 | } else {
55 | response.message = "method not allowed for this route";
56 | }
57 | } else if (url.pathname === "/users") {
58 | switch (method) {
59 | case "GET":
60 | response.message = "fetching all users";
61 | response.data = users;
62 |
63 | break;
64 |
65 | case "POST":
66 | response.message = "Creating a new user";
67 |
68 | break;
69 |
70 | default:
71 | response.message = "method not allowed for this route";
72 | break;
73 | }
74 | }
75 |
76 | return Response.json(response);
77 | },
78 | });
79 |
80 | console.log(`Bun server is running on http://localhost:${server.port}`);
81 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/features/sqllite.ts:
--------------------------------------------------------------------------------
1 | import { Database } from "bun:sqlite";
2 |
3 | async function sqliteDemo() {
4 | const db = new Database("bundb.sqlite");
5 |
6 | //create a table
7 | db.run(`
8 | CREATE TABLE IF NOT EXISTS users (
9 | id INTEGER PRIMARY KEY AUTOINCREMENT,
10 | name TEXT NOT NULL,
11 | email TEXT UNIQUE NOT NULL,
12 | created_at DATETIME DEFAULT CURRENT_TIMESTAMP
13 | )
14 | `);
15 |
16 | console.log("Table users created successfully!");
17 |
18 | const insertUser = db.prepare(
19 | `INSERT INTO users (name, email) VALUES (?, ?)`
20 | ); // SQL Injection
21 | // insertUser.run("Sangam Mukherjee", "sangam@gmail.com");
22 | // insertUser.run("John Doe", "johndoe@gmail.com");
23 | // insertUser.run("James Corden", "james12345@gmail.com");
24 |
25 | // const extractAllUsers = db.query("SELECT * FROM users").all();
26 | // console.log(extractAllUsers);
27 |
28 | // db.run("UPDATE users SET name = ? WHERE email = ?", [
29 | // "Raj Mukherjee",
30 | // "sangam@gmail.com",
31 | // ]);
32 |
33 | // const getUpdatedUserInfo = db
34 | // .query("SELECT * FROM users WHERE email = ?")
35 | // .get("sangam@gmail.com");
36 | // console.log(getUpdatedUserInfo);
37 |
38 | db.run("DELETE FROM users WHERE email = ?", ["james12345@gmail.com"]);
39 | const extractRemainingUsers = db.query("SELECT * FROM users").all();
40 |
41 | console.log("extractRemainingUsers", extractRemainingUsers);
42 | }
43 |
44 | sqliteDemo();
45 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/index.ts:
--------------------------------------------------------------------------------
1 | // console.log("Hello via Bun!");
2 | // console.log(3 + 4);
3 |
4 | // import "./features/fs";
5 | // import "./features/binary";
6 | // import "./features/meta-env";
7 | // console.log("Is this main module ?", import.meta.main);
8 | // import "./features/fetch";
9 | // import "./features/server";
10 | // import "./features/hashing";
11 | import "./features/sqllite";
12 |
--------------------------------------------------------------------------------
/bun-and-hono/concepts/output.txt:
--------------------------------------------------------------------------------
1 | Hello! I am learning Bun for the first time
--------------------------------------------------------------------------------
/bun-and-hono/concepts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "concepts",
3 | "module": "index.ts",
4 | "type": "module",
5 | "devDependencies": {
6 | "@types/bun": "latest"
7 | },
8 | "peerDependencies": {
9 | "typescript": "^5.0.0"
10 | }
11 | }
--------------------------------------------------------------------------------
/bun-and-hono/concepts/read.txt:
--------------------------------------------------------------------------------
1 | Read the content from this file
--------------------------------------------------------------------------------
/bun-and-hono/concepts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | // Enable latest features
4 | "lib": ["ESNext", "DOM"],
5 | "target": "ESNext",
6 | "module": "ESNext",
7 | "moduleDetection": "force",
8 | "jsx": "react-jsx",
9 | "allowJs": true,
10 |
11 | // Bundler mode
12 | "moduleResolution": "bundler",
13 | "allowImportingTsExtensions": true,
14 | "verbatimModuleSyntax": true,
15 | "noEmit": true,
16 |
17 | // Best practices
18 | "strict": true,
19 | "skipLibCheck": true,
20 | "noFallthroughCasesInSwitch": true,
21 |
22 | // Some stricter flags (disabled by default)
23 | "noUnusedLocals": false,
24 | "noUnusedParameters": false,
25 | "noPropertyAccessFromIndexSignature": false
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/nest-js/concepts/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 | /build
5 |
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 | pnpm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | lerna-debug.log*
14 |
15 | # OS
16 | .DS_Store
17 |
18 | # Tests
19 | /coverage
20 | /.nyc_output
21 |
22 | # IDEs and editors
23 | /.idea
24 | .project
25 | .classpath
26 | .c9/
27 | *.launch
28 | .settings/
29 | *.sublime-workspace
30 |
31 | # IDE - VSCode
32 | .vscode/*
33 | !.vscode/settings.json
34 | !.vscode/tasks.json
35 | !.vscode/launch.json
36 | !.vscode/extensions.json
37 |
38 | # dotenv environment variable files
39 | .env
40 | .env.development.local
41 | .env.test.local
42 | .env.production.local
43 | .env.local
44 |
45 | # temp directory
46 | .temp
47 | .tmp
48 |
49 | # Runtime data
50 | pids
51 | *.pid
52 | *.seed
53 | *.pid.lock
54 |
55 | # Diagnostic reports (https://nodejs.org/api/report.html)
56 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57 |
--------------------------------------------------------------------------------
/nest-js/concepts/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/nest-js/concepts/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6 | [circleci-url]: https://circleci.com/gh/nestjs/nest
7 |
8 | A progressive Node.js framework for building efficient and scalable server-side applications.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 | ## Description
26 |
27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
28 |
29 | ## Project setup
30 |
31 | ```bash
32 | $ npm install
33 | ```
34 |
35 | ## Compile and run the project
36 |
37 | ```bash
38 | # development
39 | $ npm run start
40 |
41 | # watch mode
42 | $ npm run start:dev
43 |
44 | # production mode
45 | $ npm run start:prod
46 | ```
47 |
48 | ## Run tests
49 |
50 | ```bash
51 | # unit tests
52 | $ npm run test
53 |
54 | # e2e tests
55 | $ npm run test:e2e
56 |
57 | # test coverage
58 | $ npm run test:cov
59 | ```
60 |
61 | ## Deployment
62 |
63 | When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
64 |
65 | If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
66 |
67 | ```bash
68 | $ npm install -g mau
69 | $ mau deploy
70 | ```
71 |
72 | With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
73 |
74 | ## Resources
75 |
76 | Check out a few resources that may come in handy when working with NestJS:
77 |
78 | - Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
79 | - For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
80 | - To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
81 | - Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
82 | - Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
83 | - Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
84 | - To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
85 | - Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
86 |
87 | ## Support
88 |
89 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
90 |
91 | ## Stay in touch
92 |
93 | - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
94 | - Website - [https://nestjs.com](https://nestjs.com/)
95 | - Twitter - [@nestframework](https://twitter.com/nestframework)
96 |
97 | ## License
98 |
99 | Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
100 |
--------------------------------------------------------------------------------
/nest-js/concepts/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import eslint from '@eslint/js';
3 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4 | import globals from 'globals';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | {
9 | ignores: ['eslint.config.mjs'],
10 | },
11 | eslint.configs.recommended,
12 | ...tseslint.configs.recommendedTypeChecked,
13 | eslintPluginPrettierRecommended,
14 | {
15 | languageOptions: {
16 | globals: {
17 | ...globals.node,
18 | ...globals.jest,
19 | },
20 | ecmaVersion: 5,
21 | sourceType: 'module',
22 | parserOptions: {
23 | projectService: true,
24 | tsconfigRootDir: import.meta.dirname,
25 | },
26 | },
27 | },
28 | {
29 | rules: {
30 | '@typescript-eslint/no-explicit-any': 'off',
31 | '@typescript-eslint/no-floating-promises': 'warn',
32 | '@typescript-eslint/no-unsafe-argument': 'warn'
33 | },
34 | },
35 | );
--------------------------------------------------------------------------------
/nest-js/concepts/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nest-js/concepts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "concepts",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "build": "nest build",
10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
11 | "start": "nest start",
12 | "start:dev": "nest start --watch",
13 | "start:debug": "nest start --debug --watch",
14 | "start:prod": "node dist/main",
15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
16 | "test": "jest",
17 | "test:watch": "jest --watch",
18 | "test:cov": "jest --coverage",
19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
20 | "test:e2e": "jest --config ./test/jest-e2e.json"
21 | },
22 | "dependencies": {
23 | "@nestjs/common": "^11.0.1",
24 | "@nestjs/core": "^11.0.1",
25 | "@nestjs/platform-express": "^11.0.1",
26 | "reflect-metadata": "^0.2.2",
27 | "rxjs": "^7.8.1"
28 | },
29 | "devDependencies": {
30 | "@eslint/eslintrc": "^3.2.0",
31 | "@eslint/js": "^9.18.0",
32 | "@nestjs/cli": "^11.0.0",
33 | "@nestjs/schematics": "^11.0.0",
34 | "@nestjs/testing": "^11.0.1",
35 | "@swc/cli": "^0.6.0",
36 | "@swc/core": "^1.10.7",
37 | "@types/express": "^5.0.0",
38 | "@types/jest": "^29.5.14",
39 | "@types/node": "^22.10.7",
40 | "@types/supertest": "^6.0.2",
41 | "eslint": "^9.18.0",
42 | "eslint-config-prettier": "^10.0.1",
43 | "eslint-plugin-prettier": "^5.2.2",
44 | "globals": "^15.14.0",
45 | "jest": "^29.7.0",
46 | "prettier": "^3.4.2",
47 | "source-map-support": "^0.5.21",
48 | "supertest": "^7.0.0",
49 | "ts-jest": "^29.2.5",
50 | "ts-loader": "^9.5.2",
51 | "ts-node": "^10.9.2",
52 | "tsconfig-paths": "^4.2.0",
53 | "typescript": "^5.7.3",
54 | "typescript-eslint": "^8.20.0"
55 | },
56 | "jest": {
57 | "moduleFileExtensions": [
58 | "js",
59 | "json",
60 | "ts"
61 | ],
62 | "rootDir": "src",
63 | "testRegex": ".*\\.spec\\.ts$",
64 | "transform": {
65 | "^.+\\.(t|j)s$": "ts-jest"
66 | },
67 | "collectCoverageFrom": [
68 | "**/*.(t|j)s"
69 | ],
70 | "coverageDirectory": "../coverage",
71 | "testEnvironment": "node"
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | //AppService is injected through the constructor
7 | //constructor based dependency injection
8 | constructor(private readonly appService: AppService) {}
9 |
10 | @Get()
11 | getHello(): string {
12 | //using the injected service to get the gethello method
13 | return this.appService.getHello();
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 | import { BlogModule } from './blog/blog.module';
5 |
6 | // -> Root module which imports all other modules
7 |
8 | //Modules -> group related providers and controllers together
9 |
10 | @Module({
11 | imports: [BlogModule],
12 | controllers: [AppController],
13 | providers: [AppService],
14 | })
15 | export class AppModule {}
16 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | //decorator
4 | //business logics of your application
5 | @Injectable()
6 | export class AppService {
7 | getHello(): string {
8 | return 'Hello Nest JS!';
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/blog/blog.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { BlogController } from './blog.controller';
3 |
4 | describe('BlogController', () => {
5 | let controller: BlogController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [BlogController],
10 | }).compile();
11 |
12 | controller = module.get(BlogController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/blog/blog.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get, Param } from '@nestjs/common';
2 | import { BlogService } from './blog.service';
3 |
4 | @Controller('blog')
5 | export class BlogController {
6 | constructor(private readonly blogService: BlogService) {}
7 | @Get()
8 | findAll() {
9 | return this.blogService.findAll();
10 | }
11 |
12 | @Get(':id')
13 | findById(@Param('id') id: string) {
14 | return this.blogService.findById(+id);
15 | }
16 |
17 | @Get('by-unique-key/:key')
18 | findByBlogUniqueKey(@Param('key') key: string) {
19 | return this.blogService.findByUniqueKey(key);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/blog/blog.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { BlogController } from './blog.controller';
3 | import { BlogService } from './blog.service';
4 |
5 | @Module({
6 | controllers: [BlogController],
7 | providers: [BlogService]
8 | })
9 | export class BlogModule {}
10 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/blog/blog.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { BlogService } from './blog.service';
3 |
4 | describe('BlogService', () => {
5 | let service: BlogService;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | providers: [BlogService],
10 | }).compile();
11 |
12 | service = module.get(BlogService);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(service).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/blog/blog.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class BlogService {
5 | private readonly blogs = [
6 | {
7 | id: 1,
8 | blogTitle: 'Blog 1',
9 | blogUniqueKey: 'blogUniqueKey1',
10 | },
11 | {
12 | id: 2,
13 | blogTitle: 'Blog 2',
14 | blogUniqueKey: 'blogUniqueKey2',
15 | },
16 | {
17 | id: 3,
18 | blogTitle: 'Blog 3',
19 | blogUniqueKey: 'blogUniqueKey3',
20 | },
21 | {
22 | id: 4,
23 | blogTitle: 'Blog 4',
24 | blogUniqueKey: 'blogUniqueKey4',
25 | },
26 | {
27 | id: 5,
28 | blogTitle: 'Blog 5',
29 | blogUniqueKey: 'blogUniqueKey5',
30 | },
31 | ];
32 |
33 | findAll() {
34 | return this.blogs;
35 | }
36 |
37 | findById(id: number) {
38 | return this.blogs.find((blog) => blog.id === id);
39 | }
40 |
41 | findByUniqueKey(key: string) {
42 | return this.blogs.find((blog) => blog.blogUniqueKey === key);
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/nest-js/concepts/src/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { AppModule } from './app.module';
3 |
4 | async function bootstrap() {
5 | //create a nest js application instance
6 | const app = await NestFactory.create(AppModule);
7 |
8 | //start the application anf listen to this port
9 | await app.listen(process.env.PORT ?? 3000);
10 | }
11 | bootstrap();
12 |
--------------------------------------------------------------------------------
/nest-js/concepts/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { App } from 'supertest/types';
5 | import { AppModule } from './../src/app.module';
6 |
7 | describe('AppController (e2e)', () => {
8 | let app: INestApplication;
9 |
10 | beforeEach(async () => {
11 | const moduleFixture: TestingModule = await Test.createTestingModule({
12 | imports: [AppModule],
13 | }).compile();
14 |
15 | app = moduleFixture.createNestApplication();
16 | await app.init();
17 | });
18 |
19 | it('/ (GET)', () => {
20 | return request(app.getHttpServer())
21 | .get('/')
22 | .expect(200)
23 | .expect('Hello World!');
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nest-js/concepts/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/nest-js/concepts/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/nest-js/concepts/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "ES2023",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true,
14 | "skipLibCheck": true,
15 | "strictNullChecks": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "noImplicitAny": false,
18 | "strictBindCallApply": false,
19 | "noFallthroughCasesInSwitch": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/nest-js/file-upload/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 | /build
5 |
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 | pnpm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | lerna-debug.log*
14 |
15 | # OS
16 | .DS_Store
17 |
18 | # Tests
19 | /coverage
20 | /.nyc_output
21 |
22 | # IDEs and editors
23 | /.idea
24 | .project
25 | .classpath
26 | .c9/
27 | *.launch
28 | .settings/
29 | *.sublime-workspace
30 |
31 | # IDE - VSCode
32 | .vscode/*
33 | !.vscode/settings.json
34 | !.vscode/tasks.json
35 | !.vscode/launch.json
36 | !.vscode/extensions.json
37 |
38 | # dotenv environment variable files
39 | .env
40 | .env.development.local
41 | .env.test.local
42 | .env.production.local
43 | .env.local
44 |
45 | # temp directory
46 | .temp
47 | .tmp
48 |
49 | # Runtime data
50 | pids
51 | *.pid
52 | *.seed
53 | *.pid.lock
54 |
55 | # Diagnostic reports (https://nodejs.org/api/report.html)
56 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57 |
--------------------------------------------------------------------------------
/nest-js/file-upload/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/nest-js/file-upload/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6 | [circleci-url]: https://circleci.com/gh/nestjs/nest
7 |
8 | A progressive Node.js framework for building efficient and scalable server-side applications.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 | ## Description
26 |
27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
28 |
29 | ## Project setup
30 |
31 | ```bash
32 | $ npm install
33 | ```
34 |
35 | ## Compile and run the project
36 |
37 | ```bash
38 | # development
39 | $ npm run start
40 |
41 | # watch mode
42 | $ npm run start:dev
43 |
44 | # production mode
45 | $ npm run start:prod
46 | ```
47 |
48 | ## Run tests
49 |
50 | ```bash
51 | # unit tests
52 | $ npm run test
53 |
54 | # e2e tests
55 | $ npm run test:e2e
56 |
57 | # test coverage
58 | $ npm run test:cov
59 | ```
60 |
61 | ## Deployment
62 |
63 | When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
64 |
65 | If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
66 |
67 | ```bash
68 | $ npm install -g mau
69 | $ mau deploy
70 | ```
71 |
72 | With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
73 |
74 | ## Resources
75 |
76 | Check out a few resources that may come in handy when working with NestJS:
77 |
78 | - Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
79 | - For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
80 | - To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
81 | - Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
82 | - Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
83 | - Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
84 | - To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
85 | - Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
86 |
87 | ## Support
88 |
89 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
90 |
91 | ## Stay in touch
92 |
93 | - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
94 | - Website - [https://nestjs.com](https://nestjs.com/)
95 | - Twitter - [@nestframework](https://twitter.com/nestframework)
96 |
97 | ## License
98 |
99 | Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
100 |
--------------------------------------------------------------------------------
/nest-js/file-upload/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import eslint from '@eslint/js';
3 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4 | import globals from 'globals';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | {
9 | ignores: ['eslint.config.mjs'],
10 | },
11 | eslint.configs.recommended,
12 | ...tseslint.configs.recommendedTypeChecked,
13 | eslintPluginPrettierRecommended,
14 | {
15 | languageOptions: {
16 | globals: {
17 | ...globals.node,
18 | ...globals.jest,
19 | },
20 | ecmaVersion: 5,
21 | sourceType: 'module',
22 | parserOptions: {
23 | projectService: true,
24 | tsconfigRootDir: import.meta.dirname,
25 | },
26 | },
27 | },
28 | {
29 | rules: {
30 | '@typescript-eslint/no-explicit-any': 'off',
31 | '@typescript-eslint/no-floating-promises': 'warn',
32 | '@typescript-eslint/no-unsafe-argument': 'warn'
33 | },
34 | },
35 | );
--------------------------------------------------------------------------------
/nest-js/file-upload/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nest-js/file-upload/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file-upload",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "build": "nest build",
10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
11 | "start": "nest start",
12 | "start:dev": "nest start --watch",
13 | "start:debug": "nest start --debug --watch",
14 | "start:prod": "node dist/main",
15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
16 | "test": "jest",
17 | "test:watch": "jest --watch",
18 | "test:cov": "jest --coverage",
19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
20 | "test:e2e": "jest --config ./test/jest-e2e.json"
21 | },
22 | "dependencies": {
23 | "@nestjs/common": "^11.0.1",
24 | "@nestjs/config": "^4.0.0",
25 | "@nestjs/core": "^11.0.1",
26 | "@nestjs/platform-express": "^11.0.11",
27 | "@prisma/client": "^6.4.1",
28 | "@types/multer": "^1.4.12",
29 | "cloudinary": "^2.5.1",
30 | "multer": "^1.4.5-lts.1",
31 | "prisma": "^6.4.1",
32 | "reflect-metadata": "^0.2.2",
33 | "rxjs": "^7.8.1"
34 | },
35 | "devDependencies": {
36 | "@eslint/eslintrc": "^3.2.0",
37 | "@eslint/js": "^9.18.0",
38 | "@nestjs/cli": "^11.0.0",
39 | "@nestjs/schematics": "^11.0.0",
40 | "@nestjs/testing": "^11.0.1",
41 | "@swc/cli": "^0.6.0",
42 | "@swc/core": "^1.10.7",
43 | "@types/express": "^5.0.0",
44 | "@types/jest": "^29.5.14",
45 | "@types/node": "^22.10.7",
46 | "@types/supertest": "^6.0.2",
47 | "eslint": "^9.18.0",
48 | "eslint-config-prettier": "^10.0.1",
49 | "eslint-plugin-prettier": "^5.2.2",
50 | "globals": "^15.14.0",
51 | "jest": "^29.7.0",
52 | "prettier": "^3.4.2",
53 | "source-map-support": "^0.5.21",
54 | "supertest": "^7.0.0",
55 | "ts-jest": "^29.2.5",
56 | "ts-loader": "^9.5.2",
57 | "ts-node": "^10.9.2",
58 | "tsconfig-paths": "^4.2.0",
59 | "typescript": "^5.7.3",
60 | "typescript-eslint": "^8.20.0"
61 | },
62 | "jest": {
63 | "moduleFileExtensions": [
64 | "js",
65 | "json",
66 | "ts"
67 | ],
68 | "rootDir": "src",
69 | "testRegex": ".*\\.spec\\.ts$",
70 | "transform": {
71 | "^.+\\.(t|j)s$": "ts-jest"
72 | },
73 | "collectCoverageFrom": [
74 | "**/*.(t|j)s"
75 | ],
76 | "coverageDirectory": "../coverage",
77 | "testEnvironment": "node"
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/nest-js/file-upload/prisma/migrations/20250302190131_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "File" (
3 | "id" TEXT NOT NULL,
4 | "filename" TEXT NOT NULL,
5 | "publicId" TEXT NOT NULL,
6 | "url" TEXT NOT NULL,
7 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
8 | "updatedAt" TIMESTAMP(3) NOT NULL,
9 |
10 | CONSTRAINT "File_pkey" PRIMARY KEY ("id")
11 | );
12 |
13 | -- CreateIndex
14 | CREATE UNIQUE INDEX "File_publicId_key" ON "File"("publicId");
15 |
--------------------------------------------------------------------------------
/nest-js/file-upload/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (e.g., Git)
3 | provider = "postgresql"
--------------------------------------------------------------------------------
/nest-js/file-upload/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6 |
7 | generator client {
8 | provider = "prisma-client-js"
9 | }
10 |
11 | datasource db {
12 | provider = "postgresql"
13 | url = env("DATABASE_URL")
14 | }
15 |
16 | model File {
17 | id String @id @default(uuid())
18 | filename String
19 | publicId String @unique
20 | url String
21 | createdAt DateTime @default(now())
22 | updatedAt DateTime @updatedAt
23 | }
24 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | constructor(private readonly appService: AppService) {}
7 |
8 | @Get()
9 | getHello(): string {
10 | return this.appService.getHello();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 | import { ConfigModule } from '@nestjs/config';
5 | import { FileUploadModule } from './file-upload/file-upload.module';
6 |
7 | @Module({
8 | imports: [
9 | ConfigModule.forRoot({
10 | isGlobal: true,
11 | }),
12 | FileUploadModule,
13 | ],
14 | controllers: [AppController],
15 | providers: [AppService],
16 | })
17 | export class AppModule {}
18 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/file-upload/file-upload.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { FileUploadController } from './file-upload.controller';
3 |
4 | describe('FileUploadController', () => {
5 | let controller: FileUploadController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [FileUploadController],
10 | }).compile();
11 |
12 | controller = module.get(FileUploadController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/file-upload/file-upload.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Controller,
3 | Delete,
4 | Param,
5 | Post,
6 | UploadedFile,
7 | UseInterceptors,
8 | } from '@nestjs/common';
9 | import { FileUploadService } from './file-upload.service';
10 | import { FileInterceptor } from '@nestjs/platform-express';
11 | import { diskStorage } from 'multer';
12 | import { extname } from 'path';
13 |
14 | @Controller('file-upload')
15 | export class FileUploadController {
16 | constructor(private readonly fileUploaderService: FileUploadService) {}
17 |
18 | @Post()
19 | @UseInterceptors(
20 | FileInterceptor('file', {
21 | storage: diskStorage({
22 | destination: './uploads',
23 | filename: (req, file, callback) => {
24 | const uniqueSuffix =
25 | Date.now() + '-' + Math.round(Math.random() * 1e9);
26 | const ext = extname(file.originalname);
27 | const filename = `${uniqueSuffix}${ext}`;
28 | callback(null, filename);
29 | },
30 | }),
31 | }),
32 | )
33 | async uploadFile(@UploadedFile() file: Express.Multer.File) {
34 | return this.fileUploaderService.uploadFile(file);
35 | }
36 |
37 | @Delete(':id')
38 | async deleteFile(@Param('id') id: string) {
39 | return this.fileUploaderService.deleteFile(id);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/file-upload/file-upload.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { FileUploadController } from './file-upload.controller';
3 | import { FileUploadService } from './file-upload.service';
4 | import { PrismaService } from 'src/prisma/prisma.service';
5 |
6 | @Module({
7 | controllers: [FileUploadController],
8 | providers: [FileUploadService, PrismaService],
9 | })
10 | export class FileUploadModule {}
11 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/file-upload/file-upload.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { FileUploadService } from './file-upload.service';
3 |
4 | describe('FileUploadService', () => {
5 | let service: FileUploadService;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | providers: [FileUploadService],
10 | }).compile();
11 |
12 | service = module.get(FileUploadService);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(service).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/file-upload/file-upload.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, InternalServerErrorException } from '@nestjs/common';
2 | import { PrismaService } from 'src/prisma/prisma.service';
3 | import { v2 as cloudinary } from 'cloudinary';
4 | import * as fs from 'fs';
5 |
6 | @Injectable()
7 | export class FileUploadService {
8 | constructor(private prisma: PrismaService) {
9 | cloudinary.config({
10 | cloud_name: process.env.CLOUDINARY_CLOUD_NAME,
11 | api_key: process.env.CLOUDINARY_API_KEY,
12 | api_secret: process.env.CLOUDINARY_API_SECRET,
13 | });
14 | }
15 |
16 | async uploadFile(file: Express.Multer.File) {
17 | try {
18 | const uploadResult = await this.uploadToCloudinary(file.path);
19 |
20 | const newlySavedFile = await this.prisma.file.create({
21 | data: {
22 | filename: file.originalname,
23 | publicId: uploadResult.public_id,
24 | url: uploadResult.secure_url,
25 | },
26 | });
27 |
28 | fs.unlinkSync(file.path);
29 |
30 | return newlySavedFile;
31 | } catch (error) {
32 | //removing in case of any error -> this file from local folder
33 | if (file.path && fs.existsSync(file.path)) {
34 | fs.unlinkSync(file.path);
35 | }
36 |
37 | throw new InternalServerErrorException(
38 | 'File upload failed! Please try again after some time',
39 | );
40 | }
41 | }
42 |
43 | private uploadToCloudinary(filePath: string): Promise {
44 | return new Promise((resolve, reject) => {
45 | cloudinary.uploader.upload(filePath, (error, result) => {
46 | if (error) reject(error);
47 | resolve(result);
48 | });
49 | });
50 | }
51 |
52 | async deleteFile(fileId: string) {
53 | try {
54 | const file = await this.prisma.file.findUnique({
55 | where: {
56 | id: fileId,
57 | },
58 | });
59 |
60 | if (!file) {
61 | throw new Error('File not found! Please try with a different file ID');
62 | }
63 |
64 | await cloudinary.uploader.destroy(file.publicId);
65 |
66 | await this.prisma.file.delete({
67 | where: { id: fileId },
68 | });
69 |
70 | return {
71 | message: 'File deleted successfully',
72 | };
73 | } catch (e) {
74 | throw new InternalServerErrorException(
75 | 'File deletion failed! Please try again after some time',
76 | );
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { AppModule } from './app.module';
3 | import * as path from 'path';
4 | import * as fs from 'fs';
5 |
6 | async function bootstrap() {
7 | const uploadDirectory = path.join(__dirname, '..', 'uploads');
8 |
9 | if (!fs.existsSync(uploadDirectory)) {
10 | fs.mkdirSync(uploadDirectory);
11 | }
12 |
13 | const app = await NestFactory.create(AppModule);
14 | await app.listen(process.env.PORT ?? 3000);
15 | }
16 | bootstrap();
17 |
--------------------------------------------------------------------------------
/nest-js/file-upload/src/prisma/prisma.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common';
2 | import { PrismaClient } from '@prisma/client';
3 |
4 | @Injectable()
5 | export class PrismaService
6 | extends PrismaClient
7 | implements OnModuleInit, OnModuleDestroy
8 | {
9 | async onModuleInit() {
10 | await this.$connect();
11 | }
12 |
13 | async onModuleDestroy() {
14 | await this.$disconnect();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/nest-js/file-upload/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { App } from 'supertest/types';
5 | import { AppModule } from './../src/app.module';
6 |
7 | describe('AppController (e2e)', () => {
8 | let app: INestApplication;
9 |
10 | beforeEach(async () => {
11 | const moduleFixture: TestingModule = await Test.createTestingModule({
12 | imports: [AppModule],
13 | }).compile();
14 |
15 | app = moduleFixture.createNestApplication();
16 | await app.init();
17 | });
18 |
19 | it('/ (GET)', () => {
20 | return request(app.getHttpServer())
21 | .get('/')
22 | .expect(200)
23 | .expect('Hello World!');
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nest-js/file-upload/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/nest-js/file-upload/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/nest-js/file-upload/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "ES2023",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true,
14 | "skipLibCheck": true,
15 | "strictNullChecks": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "noImplicitAny": false,
18 | "strictBindCallApply": false,
19 | "noFallthroughCasesInSwitch": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/.gitignore:
--------------------------------------------------------------------------------
1 | # compiled output
2 | /dist
3 | /node_modules
4 | /build
5 |
6 | # Logs
7 | logs
8 | *.log
9 | npm-debug.log*
10 | pnpm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | lerna-debug.log*
14 |
15 | # OS
16 | .DS_Store
17 |
18 | # Tests
19 | /coverage
20 | /.nyc_output
21 |
22 | # IDEs and editors
23 | /.idea
24 | .project
25 | .classpath
26 | .c9/
27 | *.launch
28 | .settings/
29 | *.sublime-workspace
30 |
31 | # IDE - VSCode
32 | .vscode/*
33 | !.vscode/settings.json
34 | !.vscode/tasks.json
35 | !.vscode/launch.json
36 | !.vscode/extensions.json
37 |
38 | # dotenv environment variable files
39 | .env
40 | .env.development.local
41 | .env.test.local
42 | .env.production.local
43 | .env.local
44 |
45 | # temp directory
46 | .temp
47 | .tmp
48 |
49 | # Runtime data
50 | pids
51 | *.pid
52 | *.seed
53 | *.pid.lock
54 |
55 | # Diagnostic reports (https://nodejs.org/api/report.html)
56 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
57 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": true,
3 | "trailingComma": "all"
4 | }
--------------------------------------------------------------------------------
/nest-js/travel-tracker/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456
6 | [circleci-url]: https://circleci.com/gh/nestjs/nest
7 |
8 | A progressive Node.js framework for building efficient and scalable server-side applications.
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
24 |
25 | ## Description
26 |
27 | [Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
28 |
29 | ## Project setup
30 |
31 | ```bash
32 | $ npm install
33 | ```
34 |
35 | ## Compile and run the project
36 |
37 | ```bash
38 | # development
39 | $ npm run start
40 |
41 | # watch mode
42 | $ npm run start:dev
43 |
44 | # production mode
45 | $ npm run start:prod
46 | ```
47 |
48 | ## Run tests
49 |
50 | ```bash
51 | # unit tests
52 | $ npm run test
53 |
54 | # e2e tests
55 | $ npm run test:e2e
56 |
57 | # test coverage
58 | $ npm run test:cov
59 | ```
60 |
61 | ## Deployment
62 |
63 | When you're ready to deploy your NestJS application to production, there are some key steps you can take to ensure it runs as efficiently as possible. Check out the [deployment documentation](https://docs.nestjs.com/deployment) for more information.
64 |
65 | If you are looking for a cloud-based platform to deploy your NestJS application, check out [Mau](https://mau.nestjs.com), our official platform for deploying NestJS applications on AWS. Mau makes deployment straightforward and fast, requiring just a few simple steps:
66 |
67 | ```bash
68 | $ npm install -g mau
69 | $ mau deploy
70 | ```
71 |
72 | With Mau, you can deploy your application in just a few clicks, allowing you to focus on building features rather than managing infrastructure.
73 |
74 | ## Resources
75 |
76 | Check out a few resources that may come in handy when working with NestJS:
77 |
78 | - Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
79 | - For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
80 | - To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
81 | - Deploy your application to AWS with the help of [NestJS Mau](https://mau.nestjs.com) in just a few clicks.
82 | - Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
83 | - Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
84 | - To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
85 | - Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
86 |
87 | ## Support
88 |
89 | Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
90 |
91 | ## Stay in touch
92 |
93 | - Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
94 | - Website - [https://nestjs.com](https://nestjs.com/)
95 | - Twitter - [@nestframework](https://twitter.com/nestframework)
96 |
97 | ## License
98 |
99 | Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).
100 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | // @ts-check
2 | import eslint from '@eslint/js';
3 | import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended';
4 | import globals from 'globals';
5 | import tseslint from 'typescript-eslint';
6 |
7 | export default tseslint.config(
8 | {
9 | ignores: ['eslint.config.mjs'],
10 | },
11 | eslint.configs.recommended,
12 | ...tseslint.configs.recommendedTypeChecked,
13 | eslintPluginPrettierRecommended,
14 | {
15 | languageOptions: {
16 | globals: {
17 | ...globals.node,
18 | ...globals.jest,
19 | },
20 | ecmaVersion: 5,
21 | sourceType: 'module',
22 | parserOptions: {
23 | projectService: true,
24 | tsconfigRootDir: import.meta.dirname,
25 | },
26 | },
27 | },
28 | {
29 | rules: {
30 | '@typescript-eslint/no-explicit-any': 'off',
31 | '@typescript-eslint/no-floating-promises': 'warn',
32 | '@typescript-eslint/no-unsafe-argument': 'warn'
33 | },
34 | },
35 | );
--------------------------------------------------------------------------------
/nest-js/travel-tracker/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/nest-cli",
3 | "collection": "@nestjs/schematics",
4 | "sourceRoot": "src",
5 | "compilerOptions": {
6 | "deleteOutDir": true
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "travel-tracker",
3 | "version": "0.0.1",
4 | "description": "",
5 | "author": "",
6 | "private": true,
7 | "license": "UNLICENSED",
8 | "scripts": {
9 | "build": "nest build",
10 | "format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
11 | "start": "nest start",
12 | "start:dev": "nest start --watch",
13 | "start:debug": "nest start --debug --watch",
14 | "start:prod": "node dist/main",
15 | "lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
16 | "test": "jest",
17 | "test:watch": "jest --watch",
18 | "test:cov": "jest --coverage",
19 | "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
20 | "test:e2e": "jest --config ./test/jest-e2e.json"
21 | },
22 | "dependencies": {
23 | "@nestjs/common": "^11.0.1",
24 | "@nestjs/config": "^4.0.0",
25 | "@nestjs/core": "^11.0.1",
26 | "@nestjs/jwt": "^11.0.0",
27 | "@nestjs/mapped-types": "^2.1.0",
28 | "@nestjs/passport": "^11.0.5",
29 | "@nestjs/platform-express": "^11.0.1",
30 | "@prisma/client": "^6.4.1",
31 | "bcrypt": "^5.1.1",
32 | "class-transformer": "^0.5.1",
33 | "class-validator": "^0.14.1",
34 | "passport-jwt": "^4.0.1",
35 | "prisma": "^6.4.1",
36 | "reflect-metadata": "^0.2.2",
37 | "rxjs": "^7.8.1"
38 | },
39 | "devDependencies": {
40 | "@eslint/eslintrc": "^3.2.0",
41 | "@eslint/js": "^9.18.0",
42 | "@nestjs/cli": "^11.0.0",
43 | "@nestjs/schematics": "^11.0.0",
44 | "@nestjs/testing": "^11.0.1",
45 | "@swc/cli": "^0.6.0",
46 | "@swc/core": "^1.10.7",
47 | "@types/bcrypt": "^5.0.2",
48 | "@types/express": "^5.0.0",
49 | "@types/jest": "^29.5.14",
50 | "@types/node": "^22.10.7",
51 | "@types/passport-jwt": "^4.0.1",
52 | "@types/supertest": "^6.0.2",
53 | "eslint": "^9.18.0",
54 | "eslint-config-prettier": "^10.0.1",
55 | "eslint-plugin-prettier": "^5.2.2",
56 | "globals": "^15.14.0",
57 | "jest": "^29.7.0",
58 | "prettier": "^3.4.2",
59 | "source-map-support": "^0.5.21",
60 | "supertest": "^7.0.0",
61 | "ts-jest": "^29.2.5",
62 | "ts-loader": "^9.5.2",
63 | "ts-node": "^10.9.2",
64 | "tsconfig-paths": "^4.2.0",
65 | "typescript": "^5.7.3",
66 | "typescript-eslint": "^8.20.0"
67 | },
68 | "jest": {
69 | "moduleFileExtensions": [
70 | "js",
71 | "json",
72 | "ts"
73 | ],
74 | "rootDir": "src",
75 | "testRegex": ".*\\.spec\\.ts$",
76 | "transform": {
77 | "^.+\\.(t|j)s$": "ts-jest"
78 | },
79 | "collectCoverageFrom": [
80 | "**/*.(t|j)s"
81 | ],
82 | "coverageDirectory": "../coverage",
83 | "testEnvironment": "node"
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/prisma/migrations/20250301182602_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "User" (
3 | "id" SERIAL NOT NULL,
4 | "email" TEXT NOT NULL,
5 | "password" TEXT NOT NULL,
6 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
7 | "updatedAt" TIMESTAMP(3) NOT NULL,
8 |
9 | CONSTRAINT "User_pkey" PRIMARY KEY ("id")
10 | );
11 |
12 | -- CreateTable
13 | CREATE TABLE "Destination" (
14 | "id" SERIAL NOT NULL,
15 | "name" TEXT NOT NULL,
16 | "travelDate" TIMESTAMP(3),
17 | "notes" TEXT,
18 | "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
19 | "updatedAt" TIMESTAMP(3) NOT NULL,
20 | "userId" INTEGER NOT NULL,
21 |
22 | CONSTRAINT "Destination_pkey" PRIMARY KEY ("id")
23 | );
24 |
25 | -- CreateIndex
26 | CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
27 |
28 | -- AddForeignKey
29 | ALTER TABLE "Destination" ADD CONSTRAINT "Destination_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
30 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (e.g., Git)
3 | provider = "postgresql"
--------------------------------------------------------------------------------
/nest-js/travel-tracker/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | // This is your Prisma schema file,
2 | // learn more about it in the docs: https://pris.ly/d/prisma-schema
3 |
4 | // Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
5 | // Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
6 |
7 | generator client {
8 | provider = "prisma-client-js"
9 | }
10 |
11 | datasource db {
12 | provider = "postgresql"
13 | url = env("DATABASE_URL")
14 | }
15 |
16 | // -> users can register and login, once login happens jwt, jwtguard
17 | // -> destination module -> auth users
18 |
19 | model User {
20 | id Int @id @default(autoincrement())
21 | email String @unique
22 | password String
23 | createdAt DateTime @default(now())
24 | updatedAt DateTime @updatedAt
25 | destinations Destination[]
26 | }
27 |
28 | model Destination {
29 | id Int @id @default(autoincrement())
30 | name String
31 | travelDate DateTime?
32 | notes String?
33 | createdAt DateTime @default(now())
34 | updatedAt DateTime @updatedAt
35 | userId Int
36 | user User @relation(fields: [userId], references: [id])
37 | }
38 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/app.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 |
5 | describe('AppController', () => {
6 | let appController: AppController;
7 |
8 | beforeEach(async () => {
9 | const app: TestingModule = await Test.createTestingModule({
10 | controllers: [AppController],
11 | providers: [AppService],
12 | }).compile();
13 |
14 | appController = app.get(AppController);
15 | });
16 |
17 | describe('root', () => {
18 | it('should return "Hello World!"', () => {
19 | expect(appController.getHello()).toBe('Hello World!');
20 | });
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/app.controller.ts:
--------------------------------------------------------------------------------
1 | import { Controller, Get } from '@nestjs/common';
2 | import { AppService } from './app.service';
3 |
4 | @Controller()
5 | export class AppController {
6 | constructor(private readonly appService: AppService) {}
7 |
8 | @Get()
9 | getHello(): string {
10 | return this.appService.getHello();
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/app.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AppController } from './app.controller';
3 | import { AppService } from './app.service';
4 | import { ConfigModule } from '@nestjs/config';
5 | import { PrismaModule } from './prisma/prisma.module';
6 | import { AuthModule } from './auth/auth.module';
7 | import { DestinationsModule } from './destinations/destinations.module';
8 |
9 | @Module({
10 | imports: [
11 | ConfigModule.forRoot({
12 | isGlobal: true,
13 | }),
14 | PrismaModule,
15 | AuthModule,
16 | DestinationsModule,
17 | ],
18 | controllers: [AppController],
19 | providers: [AppService],
20 | })
21 | export class AppModule {}
22 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/app.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 |
3 | @Injectable()
4 | export class AppService {
5 | getHello(): string {
6 | return 'Hello World!';
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/auth.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AuthController } from './auth.controller';
3 |
4 | describe('AuthController', () => {
5 | let controller: AuthController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [AuthController],
10 | }).compile();
11 |
12 | controller = module.get(AuthController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/auth.controller.ts:
--------------------------------------------------------------------------------
1 | import { Body, Controller, Post } from '@nestjs/common';
2 | import { AuthService } from './auth.service';
3 | import { RegisterDto } from './dto/register.dto';
4 | import { LoginDto } from './dto/login.dto';
5 |
6 | @Controller('auth')
7 | export class AuthController {
8 | constructor(private readonly authService: AuthService) {}
9 |
10 | @Post('register-new-user')
11 | async register(@Body() registerDto: RegisterDto) {
12 | return this.authService.register(registerDto);
13 | }
14 |
15 | @Post('login')
16 | async login(@Body() loginDto: LoginDto) {
17 | return this.authService.login(loginDto);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/auth.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { AuthController } from './auth.controller';
3 | import { AuthService } from './auth.service';
4 | import { PrismaModule } from 'src/prisma/prisma.module';
5 | import { JwtModule } from '@nestjs/jwt';
6 | import { PassportModule } from '@nestjs/passport';
7 | import { ConfigModule, ConfigService } from '@nestjs/config';
8 | import { JwtStrategy } from './jwt.strategy';
9 |
10 | @Module({
11 | imports: [
12 | PrismaModule,
13 | PassportModule,
14 | JwtModule.registerAsync({
15 | imports: [ConfigModule],
16 | useFactory: async (configService: ConfigService) => ({
17 | secret: configService.get('JWT_SECRET') || 'JWT_SECRET',
18 | signOptions: { expiresIn: '1h' },
19 | }),
20 | inject: [ConfigService],
21 | }),
22 | ConfigModule,
23 | ],
24 | controllers: [AuthController],
25 | providers: [AuthService, JwtStrategy],
26 | exports: [JwtStrategy, PassportModule],
27 | })
28 | export class AuthModule {}
29 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/auth.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { AuthService } from './auth.service';
3 |
4 | describe('AuthService', () => {
5 | let service: AuthService;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | providers: [AuthService],
10 | }).compile();
11 |
12 | service = module.get(AuthService);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(service).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/auth.service.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ConflictException,
3 | Injectable,
4 | UnauthorizedException,
5 | } from '@nestjs/common';
6 | import { PrismaService } from 'src/prisma/prisma.service';
7 | import { RegisterDto } from './dto/register.dto';
8 | import * as bcrypt from 'bcrypt';
9 | import { LoginDto } from './dto/login.dto';
10 | import { JwtService } from '@nestjs/jwt';
11 |
12 | @Injectable()
13 | export class AuthService {
14 | constructor(
15 | private prisma: PrismaService,
16 | private jwtService: JwtService,
17 | ) {}
18 |
19 | //handle the new user registration
20 | async register(registerDto: RegisterDto) {
21 | const { email, password } = registerDto;
22 | //check if the user is exists
23 | const existingUser = await this.prisma.user.findUnique({
24 | where: { email },
25 | });
26 |
27 | if (existingUser) {
28 | throw new ConflictException(
29 | 'User already exists! Please try with a different email',
30 | );
31 | }
32 | //hash the password
33 | const hashedPassword = await bcrypt.hash(password, 10);
34 | //create new user
35 | const newlyCreatedUser = await this.prisma.user.create({
36 | data: {
37 | email,
38 | password: hashedPassword,
39 | },
40 | });
41 | //remove password from the return object
42 | const { password: _, ...result } = newlyCreatedUser;
43 | return result;
44 | }
45 |
46 | async login(loginDto: LoginDto) {
47 | const { email, password } = loginDto;
48 |
49 | //find the current user by email as email is an unique property
50 | const user = await this.prisma.user.findUnique({ where: { email } });
51 | if (!user) {
52 | throw new UnauthorizedException('Invalid credentials! Please try again');
53 | }
54 |
55 | //verify the password
56 | const isPasswordValid = await bcrypt.compare(password, user.password);
57 | if (!isPasswordValid) {
58 | throw new UnauthorizedException('Invalid credentials! Please try again');
59 | }
60 |
61 | const token = this.jwtService.sign({ userId: user.id });
62 |
63 | const { password: _, ...result } = user;
64 |
65 | return { ...result, token };
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/dto/login.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsEmail, IsString, MinLength } from 'class-validator';
2 |
3 | export class LoginDto {
4 | @IsEmail({}, { message: 'Please provide a valid email address' })
5 | email: string;
6 |
7 | @IsString()
8 | @MinLength(6, { message: 'Password must be at least 6 characters long' })
9 | password: string;
10 | }
11 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/dto/register.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsEmail, IsString, MinLength } from 'class-validator';
2 |
3 | export class RegisterDto {
4 | @IsEmail({}, { message: 'Please provide a valid email address' })
5 | email: string;
6 |
7 | @IsString()
8 | @MinLength(6, { message: 'Password must be at least 6 characters long' })
9 | password: string;
10 | }
11 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/jwt-auth.guard.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { AuthGuard } from '@nestjs/passport';
3 |
4 | @Injectable()
5 | export class JwtAuthGuard extends AuthGuard('jwt') {}
6 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/auth/jwt.strategy.ts:
--------------------------------------------------------------------------------
1 | import { Injectable } from '@nestjs/common';
2 | import { ConfigService } from '@nestjs/config';
3 | import { PassportStrategy } from '@nestjs/passport';
4 | import { ExtractJwt, Strategy } from 'passport-jwt';
5 |
6 | @Injectable()
7 | export class JwtStrategy extends PassportStrategy(Strategy) {
8 | constructor(private configService: ConfigService) {
9 | super({
10 | jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
11 | ignoreExpiration: false,
12 | secretOrKey: configService.get('JWT_SECRET') || 'JWT_SECRET',
13 | });
14 | }
15 |
16 | async validate(payload: any) {
17 | return { userId: payload.userId };
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/destinations.controller.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { DestinationsController } from './destinations.controller';
3 |
4 | describe('DestinationsController', () => {
5 | let controller: DestinationsController;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | controllers: [DestinationsController],
10 | }).compile();
11 |
12 | controller = module.get(DestinationsController);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(controller).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/destinations.controller.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Body,
3 | Controller,
4 | Delete,
5 | Get,
6 | Param,
7 | Patch,
8 | Post,
9 | Request,
10 | UseGuards,
11 | } from '@nestjs/common';
12 | import { JwtAuthGuard } from 'src/auth/jwt-auth.guard';
13 | import { DestinationsService } from './destinations.service';
14 | import { CreateDestinationDto } from './dto/create-destination.dto';
15 | import { UpdateDestinationDto } from './dto/update-destination.dto';
16 |
17 | //creating new dest
18 | //fetching all desc
19 | //delete, update -> problem -> auth user ?
20 |
21 | //guard
22 |
23 | @Controller('destinations')
24 | @UseGuards(JwtAuthGuard)
25 | export class DestinationsController {
26 | constructor(private readonly destinationsService: DestinationsService) {}
27 |
28 | @Post()
29 | create(@Request() req, @Body() createDestinationDto: CreateDestinationDto) {
30 | return this.destinationsService.create(
31 | req.user.userId,
32 | createDestinationDto,
33 | );
34 | }
35 |
36 | @Get()
37 | findAll(@Request() req) {
38 | return this.destinationsService.findAll(req.user.userId);
39 | }
40 |
41 | @Get(':id')
42 | findOne(@Request() req, @Param('id') id: string) {
43 | return this.destinationsService.findOne(req.user.userId, +id);
44 | }
45 |
46 | @Patch(':id')
47 | update(
48 | @Request() req,
49 | @Param('id') id: string,
50 | @Body() updateDestinationDto: UpdateDestinationDto,
51 | ) {
52 | return this.destinationsService.update(
53 | req.user.userId,
54 | +id,
55 | updateDestinationDto,
56 | );
57 | }
58 |
59 | @Delete(':id')
60 | remove(@Request() req, @Param('id') id: string) {
61 | return this.destinationsService.removeDestination(req.user.userId, +id);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/destinations.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { DestinationsController } from './destinations.controller';
3 | import { DestinationsService } from './destinations.service';
4 |
5 | @Module({
6 | controllers: [DestinationsController],
7 | providers: [DestinationsService]
8 | })
9 | export class DestinationsModule {}
10 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/destinations.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { DestinationsService } from './destinations.service';
3 |
4 | describe('DestinationsService', () => {
5 | let service: DestinationsService;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | providers: [DestinationsService],
10 | }).compile();
11 |
12 | service = module.get(DestinationsService);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(service).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/destinations.service.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NotFoundException } from '@nestjs/common';
2 | import { PrismaService } from 'src/prisma/prisma.service';
3 | import { CreateDestinationDto } from './dto/create-destination.dto';
4 | import { UpdateDestinationDto } from './dto/update-destination.dto';
5 |
6 | @Injectable()
7 | export class DestinationsService {
8 | constructor(private prisma: PrismaService) {}
9 |
10 | async create(userId: number, createDestinationDto: CreateDestinationDto) {
11 | return this.prisma.destination.create({
12 | data: {
13 | ...createDestinationDto,
14 | travelDate: new Date(createDestinationDto.travelDate).toISOString(),
15 | userId,
16 | },
17 | });
18 | }
19 |
20 | async findAll(userId: number) {
21 | return this.prisma.destination.findMany({
22 | where: { userId },
23 | });
24 | }
25 |
26 | async findOne(userId: number, id: number) {
27 | const destination = await this.prisma.destination.findFirst({
28 | where: { id, userId },
29 | });
30 |
31 | if (!destination) {
32 | throw new NotFoundException(`Destination not found with this id ${id}`);
33 | }
34 |
35 | return destination;
36 | }
37 |
38 | async removeDestination(userId: number, id: number) {
39 | await this.findOne(userId, id);
40 |
41 | return this.prisma.destination.delete({
42 | where: { id },
43 | });
44 | }
45 |
46 | async update(
47 | userId: number,
48 | id: number,
49 | updateDestinationDto: UpdateDestinationDto,
50 | ) {
51 | await this.findOne(userId, id);
52 |
53 | return this.prisma.destination.update({
54 | where: { id },
55 | data: updateDestinationDto,
56 | });
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/dto/create-destination.dto.ts:
--------------------------------------------------------------------------------
1 | import {
2 | IsDateString,
3 | IsNotEmpty,
4 | IsOptional,
5 | IsString,
6 | } from 'class-validator';
7 |
8 | export class CreateDestinationDto {
9 | @IsNotEmpty()
10 | @IsString()
11 | name: string;
12 |
13 | @IsNotEmpty()
14 | @IsDateString()
15 | travelDate: string;
16 |
17 | @IsOptional()
18 | @IsString()
19 | notes?: string;
20 | }
21 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/destinations/dto/update-destination.dto.ts:
--------------------------------------------------------------------------------
1 | import { PartialType } from '@nestjs/mapped-types';
2 | import { CreateDestinationDto } from './create-destination.dto';
3 |
4 | export class UpdateDestinationDto extends PartialType(CreateDestinationDto) {}
5 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/main.ts:
--------------------------------------------------------------------------------
1 | import { NestFactory } from '@nestjs/core';
2 | import { AppModule } from './app.module';
3 | import { ValidationPipe } from '@nestjs/common';
4 |
5 | async function bootstrap() {
6 | const app = await NestFactory.create(AppModule);
7 | app.useGlobalPipes(new ValidationPipe());
8 | await app.listen(process.env.PORT ?? 3000);
9 | }
10 | bootstrap();
11 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/prisma/prisma.module.ts:
--------------------------------------------------------------------------------
1 | import { Global, Module } from '@nestjs/common';
2 | import { PrismaService } from './prisma.service';
3 |
4 | //makes the module as globally scoped
5 | @Global()
6 | @Module({
7 | //registering prisma service in this module
8 | providers: [PrismaService],
9 |
10 | //making sure that this PrismaService is available to other modules that will import PrismaModule
11 | exports: [PrismaService],
12 | })
13 | export class PrismaModule {}
14 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/prisma/prisma.service.spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { PrismaService } from './prisma.service';
3 |
4 | describe('PrismaService', () => {
5 | let service: PrismaService;
6 |
7 | beforeEach(async () => {
8 | const module: TestingModule = await Test.createTestingModule({
9 | providers: [PrismaService],
10 | }).compile();
11 |
12 | service = module.get(PrismaService);
13 | });
14 |
15 | it('should be defined', () => {
16 | expect(service).toBeDefined();
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/src/prisma/prisma.service.ts:
--------------------------------------------------------------------------------
1 | import {
2 | Injectable,
3 | type OnModuleDestroy,
4 | type OnModuleInit,
5 | } from '@nestjs/common';
6 | import { PrismaClient } from '@prisma/client';
7 |
8 | @Injectable()
9 | export class PrismaService
10 | extends PrismaClient
11 | implements OnModuleInit, OnModuleDestroy
12 | {
13 | async onModuleInit() {
14 | await this.$connect();
15 | }
16 |
17 | async onModuleDestroy() {
18 | await this.$disconnect();
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/test/app.e2e-spec.ts:
--------------------------------------------------------------------------------
1 | import { Test, TestingModule } from '@nestjs/testing';
2 | import { INestApplication } from '@nestjs/common';
3 | import * as request from 'supertest';
4 | import { App } from 'supertest/types';
5 | import { AppModule } from './../src/app.module';
6 |
7 | describe('AppController (e2e)', () => {
8 | let app: INestApplication;
9 |
10 | beforeEach(async () => {
11 | const moduleFixture: TestingModule = await Test.createTestingModule({
12 | imports: [AppModule],
13 | }).compile();
14 |
15 | app = moduleFixture.createNestApplication();
16 | await app.init();
17 | });
18 |
19 | it('/ (GET)', () => {
20 | return request(app.getHttpServer())
21 | .get('/')
22 | .expect(200)
23 | .expect('Hello World!');
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/nest-js/travel-tracker/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "declaration": true,
5 | "removeComments": true,
6 | "emitDecoratorMetadata": true,
7 | "experimentalDecorators": true,
8 | "allowSyntheticDefaultImports": true,
9 | "target": "ES2023",
10 | "sourceMap": true,
11 | "outDir": "./dist",
12 | "baseUrl": "./",
13 | "incremental": true,
14 | "skipLibCheck": true,
15 | "strictNullChecks": true,
16 | "forceConsistentCasingInFileNames": true,
17 | "noImplicitAny": false,
18 | "strictBindCallApply": false,
19 | "noFallthroughCasesInSwitch": false
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
3 | .env
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | # Keep environment variables out of version control
3 | .env
4 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:18
2 |
3 | WORKDIR /usr/src/app
4 |
5 | COPY package*.json ./
6 |
7 | RUN npm install
8 |
9 | COPY . .
10 |
11 | EXPOSE 3000
12 |
13 | CMD ["node", "src/server.js"]
14 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3.8'
2 |
3 | services:
4 | database:
5 | image: postgres:15
6 | container_name: postgres_prisma_db
7 | restart: always
8 | environment:
9 | POSTGRES_USER: postgres
10 | POSTGRES_PASSWORD: root
11 | postgres_prisma_db: prisma-with-postgres
12 | ports:
13 | - "5434:5432"
14 | volumes:
15 | - postgres_data:/var/lib/postgresql/data
16 |
17 | app:
18 | build: .
19 | container_name: express_prisma_api
20 | depends_on:
21 | - database
22 | environment:
23 | - DATABASE_URL=postgresql://postgres:root@database:5432/prisma-with-postgres?schema=public
24 | ports:
25 | - "3003:3000"
26 | volumes:
27 | - .:/usr/src/app
28 | - /usr/src/app/node_modules
29 | command: [ "sh", "-c", "npx prisma generate && node src/server.js" ]
30 |
31 | prometheus:
32 | image: prom/prometheus:latest
33 | container_name: prometheus_prisma
34 | restart: always
35 | volumes:
36 | - ./prometheus.yml:/etc/prometheus/prometheus.yml
37 | ports:
38 | - "9091:9090"
39 | command:
40 | - --config.file=/etc/prometheus/prometheus.yml
41 |
42 | grafana:
43 | image: grafana/grafana:latest
44 | container_name: prisma_grafana
45 | restart: always
46 | ports:
47 | - "3005:3000"
48 | volumes:
49 | - grafana_data:/var/lib/grafana
50 | environment:
51 | - GF_SECURITY_ADMIN_USER=admin
52 | - GF_SECURITY_ADMIN_PASSWORD=admin
53 | - GF_USERS_ALLOW_SIGN_UP=false
54 | depends_on:
55 | - prometheus
56 |
57 | volumes:
58 | postgres_data:
59 | grafana_data:
60 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgres-with-prisma",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "postgres-with-prisma",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "@prisma/client": "^6.4.1",
13 | "dotenv": "^16.4.7",
14 | "express": "^4.21.2",
15 | "nodemon": "^3.1.9",
16 | "prisma": "^6.4.1",
17 | "prom-client": "^15.1.3"
18 | }
19 | },
20 | "node_modules/@esbuild/aix-ppc64": {
21 | "version": "0.25.0",
22 | "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
23 | "integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
24 | "cpu": [
25 | "ppc64"
26 | ],
27 | "optional": true,
28 | "os": [
29 | "aix"
30 | ],
31 | "engines": {
32 | "node": ">=18"
33 | }
34 | },
35 | "node_modules/@esbuild/android-arm": {
36 | "version": "0.25.0",
37 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
38 | "integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
39 | "cpu": [
40 | "arm"
41 | ],
42 | "optional": true,
43 | "os": [
44 | "android"
45 | ],
46 | "engines": {
47 | "node": ">=18"
48 | }
49 | },
50 | "node_modules/@esbuild/android-arm64": {
51 | "version": "0.25.0",
52 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
53 | "integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
54 | "cpu": [
55 | "arm64"
56 | ],
57 | "optional": true,
58 | "os": [
59 | "android"
60 | ],
61 | "engines": {
62 | "node": ">=18"
63 | }
64 | },
65 | "node_modules/@esbuild/android-x64": {
66 | "version": "0.25.0",
67 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
68 | "integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
69 | "cpu": [
70 | "x64"
71 | ],
72 | "optional": true,
73 | "os": [
74 | "android"
75 | ],
76 | "engines": {
77 | "node": ">=18"
78 | }
79 | },
80 | "node_modules/@esbuild/darwin-arm64": {
81 | "version": "0.25.0",
82 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
83 | "integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
84 | "cpu": [
85 | "arm64"
86 | ],
87 | "optional": true,
88 | "os": [
89 | "darwin"
90 | ],
91 | "engines": {
92 | "node": ">=18"
93 | }
94 | },
95 | "node_modules/@esbuild/darwin-x64": {
96 | "version": "0.25.0",
97 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
98 | "integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
99 | "cpu": [
100 | "x64"
101 | ],
102 | "optional": true,
103 | "os": [
104 | "darwin"
105 | ],
106 | "engines": {
107 | "node": ">=18"
108 | }
109 | },
110 | "node_modules/@esbuild/freebsd-arm64": {
111 | "version": "0.25.0",
112 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
113 | "integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
114 | "cpu": [
115 | "arm64"
116 | ],
117 | "optional": true,
118 | "os": [
119 | "freebsd"
120 | ],
121 | "engines": {
122 | "node": ">=18"
123 | }
124 | },
125 | "node_modules/@esbuild/freebsd-x64": {
126 | "version": "0.25.0",
127 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
128 | "integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
129 | "cpu": [
130 | "x64"
131 | ],
132 | "optional": true,
133 | "os": [
134 | "freebsd"
135 | ],
136 | "engines": {
137 | "node": ">=18"
138 | }
139 | },
140 | "node_modules/@esbuild/linux-arm": {
141 | "version": "0.25.0",
142 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
143 | "integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
144 | "cpu": [
145 | "arm"
146 | ],
147 | "optional": true,
148 | "os": [
149 | "linux"
150 | ],
151 | "engines": {
152 | "node": ">=18"
153 | }
154 | },
155 | "node_modules/@esbuild/linux-arm64": {
156 | "version": "0.25.0",
157 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
158 | "integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
159 | "cpu": [
160 | "arm64"
161 | ],
162 | "optional": true,
163 | "os": [
164 | "linux"
165 | ],
166 | "engines": {
167 | "node": ">=18"
168 | }
169 | },
170 | "node_modules/@esbuild/linux-ia32": {
171 | "version": "0.25.0",
172 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
173 | "integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
174 | "cpu": [
175 | "ia32"
176 | ],
177 | "optional": true,
178 | "os": [
179 | "linux"
180 | ],
181 | "engines": {
182 | "node": ">=18"
183 | }
184 | },
185 | "node_modules/@esbuild/linux-loong64": {
186 | "version": "0.25.0",
187 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
188 | "integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
189 | "cpu": [
190 | "loong64"
191 | ],
192 | "optional": true,
193 | "os": [
194 | "linux"
195 | ],
196 | "engines": {
197 | "node": ">=18"
198 | }
199 | },
200 | "node_modules/@esbuild/linux-mips64el": {
201 | "version": "0.25.0",
202 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
203 | "integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
204 | "cpu": [
205 | "mips64el"
206 | ],
207 | "optional": true,
208 | "os": [
209 | "linux"
210 | ],
211 | "engines": {
212 | "node": ">=18"
213 | }
214 | },
215 | "node_modules/@esbuild/linux-ppc64": {
216 | "version": "0.25.0",
217 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
218 | "integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
219 | "cpu": [
220 | "ppc64"
221 | ],
222 | "optional": true,
223 | "os": [
224 | "linux"
225 | ],
226 | "engines": {
227 | "node": ">=18"
228 | }
229 | },
230 | "node_modules/@esbuild/linux-riscv64": {
231 | "version": "0.25.0",
232 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
233 | "integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
234 | "cpu": [
235 | "riscv64"
236 | ],
237 | "optional": true,
238 | "os": [
239 | "linux"
240 | ],
241 | "engines": {
242 | "node": ">=18"
243 | }
244 | },
245 | "node_modules/@esbuild/linux-s390x": {
246 | "version": "0.25.0",
247 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
248 | "integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
249 | "cpu": [
250 | "s390x"
251 | ],
252 | "optional": true,
253 | "os": [
254 | "linux"
255 | ],
256 | "engines": {
257 | "node": ">=18"
258 | }
259 | },
260 | "node_modules/@esbuild/linux-x64": {
261 | "version": "0.25.0",
262 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
263 | "integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
264 | "cpu": [
265 | "x64"
266 | ],
267 | "optional": true,
268 | "os": [
269 | "linux"
270 | ],
271 | "engines": {
272 | "node": ">=18"
273 | }
274 | },
275 | "node_modules/@esbuild/netbsd-arm64": {
276 | "version": "0.25.0",
277 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
278 | "integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
279 | "cpu": [
280 | "arm64"
281 | ],
282 | "optional": true,
283 | "os": [
284 | "netbsd"
285 | ],
286 | "engines": {
287 | "node": ">=18"
288 | }
289 | },
290 | "node_modules/@esbuild/netbsd-x64": {
291 | "version": "0.25.0",
292 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
293 | "integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
294 | "cpu": [
295 | "x64"
296 | ],
297 | "optional": true,
298 | "os": [
299 | "netbsd"
300 | ],
301 | "engines": {
302 | "node": ">=18"
303 | }
304 | },
305 | "node_modules/@esbuild/openbsd-arm64": {
306 | "version": "0.25.0",
307 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
308 | "integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
309 | "cpu": [
310 | "arm64"
311 | ],
312 | "optional": true,
313 | "os": [
314 | "openbsd"
315 | ],
316 | "engines": {
317 | "node": ">=18"
318 | }
319 | },
320 | "node_modules/@esbuild/openbsd-x64": {
321 | "version": "0.25.0",
322 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
323 | "integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
324 | "cpu": [
325 | "x64"
326 | ],
327 | "optional": true,
328 | "os": [
329 | "openbsd"
330 | ],
331 | "engines": {
332 | "node": ">=18"
333 | }
334 | },
335 | "node_modules/@esbuild/sunos-x64": {
336 | "version": "0.25.0",
337 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
338 | "integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
339 | "cpu": [
340 | "x64"
341 | ],
342 | "optional": true,
343 | "os": [
344 | "sunos"
345 | ],
346 | "engines": {
347 | "node": ">=18"
348 | }
349 | },
350 | "node_modules/@esbuild/win32-arm64": {
351 | "version": "0.25.0",
352 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
353 | "integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
354 | "cpu": [
355 | "arm64"
356 | ],
357 | "optional": true,
358 | "os": [
359 | "win32"
360 | ],
361 | "engines": {
362 | "node": ">=18"
363 | }
364 | },
365 | "node_modules/@esbuild/win32-ia32": {
366 | "version": "0.25.0",
367 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
368 | "integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
369 | "cpu": [
370 | "ia32"
371 | ],
372 | "optional": true,
373 | "os": [
374 | "win32"
375 | ],
376 | "engines": {
377 | "node": ">=18"
378 | }
379 | },
380 | "node_modules/@esbuild/win32-x64": {
381 | "version": "0.25.0",
382 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
383 | "integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
384 | "cpu": [
385 | "x64"
386 | ],
387 | "optional": true,
388 | "os": [
389 | "win32"
390 | ],
391 | "engines": {
392 | "node": ">=18"
393 | }
394 | },
395 | "node_modules/@opentelemetry/api": {
396 | "version": "1.9.0",
397 | "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz",
398 | "integrity": "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==",
399 | "engines": {
400 | "node": ">=8.0.0"
401 | }
402 | },
403 | "node_modules/@prisma/client": {
404 | "version": "6.4.1",
405 | "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.4.1.tgz",
406 | "integrity": "sha512-A7Mwx44+GVZVexT5e2GF/WcKkEkNNKbgr059xpr5mn+oUm2ZW1svhe+0TRNBwCdzhfIZ+q23jEgsNPvKD9u+6g==",
407 | "hasInstallScript": true,
408 | "engines": {
409 | "node": ">=18.18"
410 | },
411 | "peerDependencies": {
412 | "prisma": "*",
413 | "typescript": ">=5.1.0"
414 | },
415 | "peerDependenciesMeta": {
416 | "prisma": {
417 | "optional": true
418 | },
419 | "typescript": {
420 | "optional": true
421 | }
422 | }
423 | },
424 | "node_modules/@prisma/debug": {
425 | "version": "6.4.1",
426 | "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-6.4.1.tgz",
427 | "integrity": "sha512-Q9xk6yjEGIThjSD8zZegxd5tBRNHYd13GOIG0nLsanbTXATiPXCLyvlYEfvbR2ft6dlRsziQXfQGxAgv7zcMUA=="
428 | },
429 | "node_modules/@prisma/engines": {
430 | "version": "6.4.1",
431 | "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-6.4.1.tgz",
432 | "integrity": "sha512-KldENzMHtKYwsOSLThghOIdXOBEsfDuGSrxAZjMnimBiDKd3AE4JQ+Kv+gBD/x77WoV9xIPf25GXMWffXZ17BA==",
433 | "hasInstallScript": true,
434 | "dependencies": {
435 | "@prisma/debug": "6.4.1",
436 | "@prisma/engines-version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d",
437 | "@prisma/fetch-engine": "6.4.1",
438 | "@prisma/get-platform": "6.4.1"
439 | }
440 | },
441 | "node_modules/@prisma/engines-version": {
442 | "version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d",
443 | "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d.tgz",
444 | "integrity": "sha512-Xq54qw55vaCGrGgIJqyDwOq0TtjZPJEWsbQAHugk99hpDf2jcEeQhUcF+yzEsSqegBaDNLA4IC8Nn34sXmkiTQ=="
445 | },
446 | "node_modules/@prisma/fetch-engine": {
447 | "version": "6.4.1",
448 | "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-6.4.1.tgz",
449 | "integrity": "sha512-uZ5hVeTmDspx7KcaRCNoXmcReOD+84nwlO2oFvQPRQh9xiFYnnUKDz7l9bLxp8t4+25CsaNlgrgilXKSQwrIGQ==",
450 | "dependencies": {
451 | "@prisma/debug": "6.4.1",
452 | "@prisma/engines-version": "6.4.0-29.a9055b89e58b4b5bfb59600785423b1db3d0e75d",
453 | "@prisma/get-platform": "6.4.1"
454 | }
455 | },
456 | "node_modules/@prisma/get-platform": {
457 | "version": "6.4.1",
458 | "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-6.4.1.tgz",
459 | "integrity": "sha512-gXqZaDI5scDkBF8oza7fOD3Q3QMD0e0rBynlzDDZdTWbWmzjuW58PRZtj+jkvKje2+ZigCWkH8SsWZAsH6q1Yw==",
460 | "dependencies": {
461 | "@prisma/debug": "6.4.1"
462 | }
463 | },
464 | "node_modules/accepts": {
465 | "version": "1.3.8",
466 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
467 | "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
468 | "dependencies": {
469 | "mime-types": "~2.1.34",
470 | "negotiator": "0.6.3"
471 | },
472 | "engines": {
473 | "node": ">= 0.6"
474 | }
475 | },
476 | "node_modules/anymatch": {
477 | "version": "3.1.3",
478 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
479 | "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
480 | "dependencies": {
481 | "normalize-path": "^3.0.0",
482 | "picomatch": "^2.0.4"
483 | },
484 | "engines": {
485 | "node": ">= 8"
486 | }
487 | },
488 | "node_modules/array-flatten": {
489 | "version": "1.1.1",
490 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
491 | "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
492 | },
493 | "node_modules/balanced-match": {
494 | "version": "1.0.2",
495 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
496 | "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
497 | },
498 | "node_modules/binary-extensions": {
499 | "version": "2.3.0",
500 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
501 | "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
502 | "engines": {
503 | "node": ">=8"
504 | },
505 | "funding": {
506 | "url": "https://github.com/sponsors/sindresorhus"
507 | }
508 | },
509 | "node_modules/bintrees": {
510 | "version": "1.0.2",
511 | "resolved": "https://registry.npmjs.org/bintrees/-/bintrees-1.0.2.tgz",
512 | "integrity": "sha512-VOMgTMwjAaUG580SXn3LacVgjurrbMme7ZZNYGSSV7mmtY6QQRh0Eg3pwIcntQ77DErK1L0NxkbetjcoXzVwKw=="
513 | },
514 | "node_modules/body-parser": {
515 | "version": "1.20.3",
516 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
517 | "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
518 | "dependencies": {
519 | "bytes": "3.1.2",
520 | "content-type": "~1.0.5",
521 | "debug": "2.6.9",
522 | "depd": "2.0.0",
523 | "destroy": "1.2.0",
524 | "http-errors": "2.0.0",
525 | "iconv-lite": "0.4.24",
526 | "on-finished": "2.4.1",
527 | "qs": "6.13.0",
528 | "raw-body": "2.5.2",
529 | "type-is": "~1.6.18",
530 | "unpipe": "1.0.0"
531 | },
532 | "engines": {
533 | "node": ">= 0.8",
534 | "npm": "1.2.8000 || >= 1.4.16"
535 | }
536 | },
537 | "node_modules/brace-expansion": {
538 | "version": "1.1.11",
539 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
540 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
541 | "dependencies": {
542 | "balanced-match": "^1.0.0",
543 | "concat-map": "0.0.1"
544 | }
545 | },
546 | "node_modules/braces": {
547 | "version": "3.0.3",
548 | "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
549 | "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
550 | "dependencies": {
551 | "fill-range": "^7.1.1"
552 | },
553 | "engines": {
554 | "node": ">=8"
555 | }
556 | },
557 | "node_modules/bytes": {
558 | "version": "3.1.2",
559 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
560 | "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
561 | "engines": {
562 | "node": ">= 0.8"
563 | }
564 | },
565 | "node_modules/call-bind-apply-helpers": {
566 | "version": "1.0.2",
567 | "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
568 | "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
569 | "dependencies": {
570 | "es-errors": "^1.3.0",
571 | "function-bind": "^1.1.2"
572 | },
573 | "engines": {
574 | "node": ">= 0.4"
575 | }
576 | },
577 | "node_modules/call-bound": {
578 | "version": "1.0.3",
579 | "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz",
580 | "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==",
581 | "dependencies": {
582 | "call-bind-apply-helpers": "^1.0.1",
583 | "get-intrinsic": "^1.2.6"
584 | },
585 | "engines": {
586 | "node": ">= 0.4"
587 | },
588 | "funding": {
589 | "url": "https://github.com/sponsors/ljharb"
590 | }
591 | },
592 | "node_modules/chokidar": {
593 | "version": "3.6.0",
594 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
595 | "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
596 | "dependencies": {
597 | "anymatch": "~3.1.2",
598 | "braces": "~3.0.2",
599 | "glob-parent": "~5.1.2",
600 | "is-binary-path": "~2.1.0",
601 | "is-glob": "~4.0.1",
602 | "normalize-path": "~3.0.0",
603 | "readdirp": "~3.6.0"
604 | },
605 | "engines": {
606 | "node": ">= 8.10.0"
607 | },
608 | "funding": {
609 | "url": "https://paulmillr.com/funding/"
610 | },
611 | "optionalDependencies": {
612 | "fsevents": "~2.3.2"
613 | }
614 | },
615 | "node_modules/concat-map": {
616 | "version": "0.0.1",
617 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
618 | "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
619 | },
620 | "node_modules/content-disposition": {
621 | "version": "0.5.4",
622 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
623 | "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
624 | "dependencies": {
625 | "safe-buffer": "5.2.1"
626 | },
627 | "engines": {
628 | "node": ">= 0.6"
629 | }
630 | },
631 | "node_modules/content-type": {
632 | "version": "1.0.5",
633 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
634 | "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
635 | "engines": {
636 | "node": ">= 0.6"
637 | }
638 | },
639 | "node_modules/cookie": {
640 | "version": "0.7.1",
641 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
642 | "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
643 | "engines": {
644 | "node": ">= 0.6"
645 | }
646 | },
647 | "node_modules/cookie-signature": {
648 | "version": "1.0.6",
649 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
650 | "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
651 | },
652 | "node_modules/debug": {
653 | "version": "2.6.9",
654 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
655 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
656 | "dependencies": {
657 | "ms": "2.0.0"
658 | }
659 | },
660 | "node_modules/depd": {
661 | "version": "2.0.0",
662 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
663 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
664 | "engines": {
665 | "node": ">= 0.8"
666 | }
667 | },
668 | "node_modules/destroy": {
669 | "version": "1.2.0",
670 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
671 | "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
672 | "engines": {
673 | "node": ">= 0.8",
674 | "npm": "1.2.8000 || >= 1.4.16"
675 | }
676 | },
677 | "node_modules/dotenv": {
678 | "version": "16.4.7",
679 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
680 | "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
681 | "engines": {
682 | "node": ">=12"
683 | },
684 | "funding": {
685 | "url": "https://dotenvx.com"
686 | }
687 | },
688 | "node_modules/dunder-proto": {
689 | "version": "1.0.1",
690 | "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
691 | "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
692 | "dependencies": {
693 | "call-bind-apply-helpers": "^1.0.1",
694 | "es-errors": "^1.3.0",
695 | "gopd": "^1.2.0"
696 | },
697 | "engines": {
698 | "node": ">= 0.4"
699 | }
700 | },
701 | "node_modules/ee-first": {
702 | "version": "1.1.1",
703 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
704 | "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
705 | },
706 | "node_modules/encodeurl": {
707 | "version": "2.0.0",
708 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz",
709 | "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==",
710 | "engines": {
711 | "node": ">= 0.8"
712 | }
713 | },
714 | "node_modules/es-define-property": {
715 | "version": "1.0.1",
716 | "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
717 | "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
718 | "engines": {
719 | "node": ">= 0.4"
720 | }
721 | },
722 | "node_modules/es-errors": {
723 | "version": "1.3.0",
724 | "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
725 | "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
726 | "engines": {
727 | "node": ">= 0.4"
728 | }
729 | },
730 | "node_modules/es-object-atoms": {
731 | "version": "1.1.1",
732 | "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
733 | "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
734 | "dependencies": {
735 | "es-errors": "^1.3.0"
736 | },
737 | "engines": {
738 | "node": ">= 0.4"
739 | }
740 | },
741 | "node_modules/esbuild": {
742 | "version": "0.25.0",
743 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
744 | "integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
745 | "hasInstallScript": true,
746 | "bin": {
747 | "esbuild": "bin/esbuild"
748 | },
749 | "engines": {
750 | "node": ">=18"
751 | },
752 | "optionalDependencies": {
753 | "@esbuild/aix-ppc64": "0.25.0",
754 | "@esbuild/android-arm": "0.25.0",
755 | "@esbuild/android-arm64": "0.25.0",
756 | "@esbuild/android-x64": "0.25.0",
757 | "@esbuild/darwin-arm64": "0.25.0",
758 | "@esbuild/darwin-x64": "0.25.0",
759 | "@esbuild/freebsd-arm64": "0.25.0",
760 | "@esbuild/freebsd-x64": "0.25.0",
761 | "@esbuild/linux-arm": "0.25.0",
762 | "@esbuild/linux-arm64": "0.25.0",
763 | "@esbuild/linux-ia32": "0.25.0",
764 | "@esbuild/linux-loong64": "0.25.0",
765 | "@esbuild/linux-mips64el": "0.25.0",
766 | "@esbuild/linux-ppc64": "0.25.0",
767 | "@esbuild/linux-riscv64": "0.25.0",
768 | "@esbuild/linux-s390x": "0.25.0",
769 | "@esbuild/linux-x64": "0.25.0",
770 | "@esbuild/netbsd-arm64": "0.25.0",
771 | "@esbuild/netbsd-x64": "0.25.0",
772 | "@esbuild/openbsd-arm64": "0.25.0",
773 | "@esbuild/openbsd-x64": "0.25.0",
774 | "@esbuild/sunos-x64": "0.25.0",
775 | "@esbuild/win32-arm64": "0.25.0",
776 | "@esbuild/win32-ia32": "0.25.0",
777 | "@esbuild/win32-x64": "0.25.0"
778 | }
779 | },
780 | "node_modules/esbuild-register": {
781 | "version": "3.6.0",
782 | "resolved": "https://registry.npmjs.org/esbuild-register/-/esbuild-register-3.6.0.tgz",
783 | "integrity": "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==",
784 | "dependencies": {
785 | "debug": "^4.3.4"
786 | },
787 | "peerDependencies": {
788 | "esbuild": ">=0.12 <1"
789 | }
790 | },
791 | "node_modules/esbuild-register/node_modules/debug": {
792 | "version": "4.4.0",
793 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
794 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
795 | "dependencies": {
796 | "ms": "^2.1.3"
797 | },
798 | "engines": {
799 | "node": ">=6.0"
800 | },
801 | "peerDependenciesMeta": {
802 | "supports-color": {
803 | "optional": true
804 | }
805 | }
806 | },
807 | "node_modules/esbuild-register/node_modules/ms": {
808 | "version": "2.1.3",
809 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
810 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
811 | },
812 | "node_modules/escape-html": {
813 | "version": "1.0.3",
814 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
815 | "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
816 | },
817 | "node_modules/etag": {
818 | "version": "1.8.1",
819 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
820 | "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
821 | "engines": {
822 | "node": ">= 0.6"
823 | }
824 | },
825 | "node_modules/express": {
826 | "version": "4.21.2",
827 | "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz",
828 | "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==",
829 | "dependencies": {
830 | "accepts": "~1.3.8",
831 | "array-flatten": "1.1.1",
832 | "body-parser": "1.20.3",
833 | "content-disposition": "0.5.4",
834 | "content-type": "~1.0.4",
835 | "cookie": "0.7.1",
836 | "cookie-signature": "1.0.6",
837 | "debug": "2.6.9",
838 | "depd": "2.0.0",
839 | "encodeurl": "~2.0.0",
840 | "escape-html": "~1.0.3",
841 | "etag": "~1.8.1",
842 | "finalhandler": "1.3.1",
843 | "fresh": "0.5.2",
844 | "http-errors": "2.0.0",
845 | "merge-descriptors": "1.0.3",
846 | "methods": "~1.1.2",
847 | "on-finished": "2.4.1",
848 | "parseurl": "~1.3.3",
849 | "path-to-regexp": "0.1.12",
850 | "proxy-addr": "~2.0.7",
851 | "qs": "6.13.0",
852 | "range-parser": "~1.2.1",
853 | "safe-buffer": "5.2.1",
854 | "send": "0.19.0",
855 | "serve-static": "1.16.2",
856 | "setprototypeof": "1.2.0",
857 | "statuses": "2.0.1",
858 | "type-is": "~1.6.18",
859 | "utils-merge": "1.0.1",
860 | "vary": "~1.1.2"
861 | },
862 | "engines": {
863 | "node": ">= 0.10.0"
864 | },
865 | "funding": {
866 | "type": "opencollective",
867 | "url": "https://opencollective.com/express"
868 | }
869 | },
870 | "node_modules/fill-range": {
871 | "version": "7.1.1",
872 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
873 | "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
874 | "dependencies": {
875 | "to-regex-range": "^5.0.1"
876 | },
877 | "engines": {
878 | "node": ">=8"
879 | }
880 | },
881 | "node_modules/finalhandler": {
882 | "version": "1.3.1",
883 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz",
884 | "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==",
885 | "dependencies": {
886 | "debug": "2.6.9",
887 | "encodeurl": "~2.0.0",
888 | "escape-html": "~1.0.3",
889 | "on-finished": "2.4.1",
890 | "parseurl": "~1.3.3",
891 | "statuses": "2.0.1",
892 | "unpipe": "~1.0.0"
893 | },
894 | "engines": {
895 | "node": ">= 0.8"
896 | }
897 | },
898 | "node_modules/forwarded": {
899 | "version": "0.2.0",
900 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
901 | "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
902 | "engines": {
903 | "node": ">= 0.6"
904 | }
905 | },
906 | "node_modules/fresh": {
907 | "version": "0.5.2",
908 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
909 | "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
910 | "engines": {
911 | "node": ">= 0.6"
912 | }
913 | },
914 | "node_modules/fsevents": {
915 | "version": "2.3.3",
916 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
917 | "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
918 | "hasInstallScript": true,
919 | "optional": true,
920 | "os": [
921 | "darwin"
922 | ],
923 | "engines": {
924 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
925 | }
926 | },
927 | "node_modules/function-bind": {
928 | "version": "1.1.2",
929 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
930 | "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
931 | "funding": {
932 | "url": "https://github.com/sponsors/ljharb"
933 | }
934 | },
935 | "node_modules/get-intrinsic": {
936 | "version": "1.3.0",
937 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
938 | "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
939 | "dependencies": {
940 | "call-bind-apply-helpers": "^1.0.2",
941 | "es-define-property": "^1.0.1",
942 | "es-errors": "^1.3.0",
943 | "es-object-atoms": "^1.1.1",
944 | "function-bind": "^1.1.2",
945 | "get-proto": "^1.0.1",
946 | "gopd": "^1.2.0",
947 | "has-symbols": "^1.1.0",
948 | "hasown": "^2.0.2",
949 | "math-intrinsics": "^1.1.0"
950 | },
951 | "engines": {
952 | "node": ">= 0.4"
953 | },
954 | "funding": {
955 | "url": "https://github.com/sponsors/ljharb"
956 | }
957 | },
958 | "node_modules/get-proto": {
959 | "version": "1.0.1",
960 | "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
961 | "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
962 | "dependencies": {
963 | "dunder-proto": "^1.0.1",
964 | "es-object-atoms": "^1.0.0"
965 | },
966 | "engines": {
967 | "node": ">= 0.4"
968 | }
969 | },
970 | "node_modules/glob-parent": {
971 | "version": "5.1.2",
972 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
973 | "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
974 | "dependencies": {
975 | "is-glob": "^4.0.1"
976 | },
977 | "engines": {
978 | "node": ">= 6"
979 | }
980 | },
981 | "node_modules/gopd": {
982 | "version": "1.2.0",
983 | "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
984 | "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
985 | "engines": {
986 | "node": ">= 0.4"
987 | },
988 | "funding": {
989 | "url": "https://github.com/sponsors/ljharb"
990 | }
991 | },
992 | "node_modules/has-flag": {
993 | "version": "3.0.0",
994 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
995 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
996 | "engines": {
997 | "node": ">=4"
998 | }
999 | },
1000 | "node_modules/has-symbols": {
1001 | "version": "1.1.0",
1002 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
1003 | "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
1004 | "engines": {
1005 | "node": ">= 0.4"
1006 | },
1007 | "funding": {
1008 | "url": "https://github.com/sponsors/ljharb"
1009 | }
1010 | },
1011 | "node_modules/hasown": {
1012 | "version": "2.0.2",
1013 | "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
1014 | "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
1015 | "dependencies": {
1016 | "function-bind": "^1.1.2"
1017 | },
1018 | "engines": {
1019 | "node": ">= 0.4"
1020 | }
1021 | },
1022 | "node_modules/http-errors": {
1023 | "version": "2.0.0",
1024 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
1025 | "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
1026 | "dependencies": {
1027 | "depd": "2.0.0",
1028 | "inherits": "2.0.4",
1029 | "setprototypeof": "1.2.0",
1030 | "statuses": "2.0.1",
1031 | "toidentifier": "1.0.1"
1032 | },
1033 | "engines": {
1034 | "node": ">= 0.8"
1035 | }
1036 | },
1037 | "node_modules/iconv-lite": {
1038 | "version": "0.4.24",
1039 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1040 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1041 | "dependencies": {
1042 | "safer-buffer": ">= 2.1.2 < 3"
1043 | },
1044 | "engines": {
1045 | "node": ">=0.10.0"
1046 | }
1047 | },
1048 | "node_modules/ignore-by-default": {
1049 | "version": "1.0.1",
1050 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
1051 | "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA=="
1052 | },
1053 | "node_modules/inherits": {
1054 | "version": "2.0.4",
1055 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
1056 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
1057 | },
1058 | "node_modules/ipaddr.js": {
1059 | "version": "1.9.1",
1060 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
1061 | "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
1062 | "engines": {
1063 | "node": ">= 0.10"
1064 | }
1065 | },
1066 | "node_modules/is-binary-path": {
1067 | "version": "2.1.0",
1068 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
1069 | "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
1070 | "dependencies": {
1071 | "binary-extensions": "^2.0.0"
1072 | },
1073 | "engines": {
1074 | "node": ">=8"
1075 | }
1076 | },
1077 | "node_modules/is-extglob": {
1078 | "version": "2.1.1",
1079 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
1080 | "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
1081 | "engines": {
1082 | "node": ">=0.10.0"
1083 | }
1084 | },
1085 | "node_modules/is-glob": {
1086 | "version": "4.0.3",
1087 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
1088 | "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
1089 | "dependencies": {
1090 | "is-extglob": "^2.1.1"
1091 | },
1092 | "engines": {
1093 | "node": ">=0.10.0"
1094 | }
1095 | },
1096 | "node_modules/is-number": {
1097 | "version": "7.0.0",
1098 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
1099 | "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
1100 | "engines": {
1101 | "node": ">=0.12.0"
1102 | }
1103 | },
1104 | "node_modules/math-intrinsics": {
1105 | "version": "1.1.0",
1106 | "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
1107 | "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
1108 | "engines": {
1109 | "node": ">= 0.4"
1110 | }
1111 | },
1112 | "node_modules/media-typer": {
1113 | "version": "0.3.0",
1114 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
1115 | "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
1116 | "engines": {
1117 | "node": ">= 0.6"
1118 | }
1119 | },
1120 | "node_modules/merge-descriptors": {
1121 | "version": "1.0.3",
1122 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
1123 | "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
1124 | "funding": {
1125 | "url": "https://github.com/sponsors/sindresorhus"
1126 | }
1127 | },
1128 | "node_modules/methods": {
1129 | "version": "1.1.2",
1130 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
1131 | "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
1132 | "engines": {
1133 | "node": ">= 0.6"
1134 | }
1135 | },
1136 | "node_modules/mime": {
1137 | "version": "1.6.0",
1138 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
1139 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
1140 | "bin": {
1141 | "mime": "cli.js"
1142 | },
1143 | "engines": {
1144 | "node": ">=4"
1145 | }
1146 | },
1147 | "node_modules/mime-db": {
1148 | "version": "1.52.0",
1149 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
1150 | "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
1151 | "engines": {
1152 | "node": ">= 0.6"
1153 | }
1154 | },
1155 | "node_modules/mime-types": {
1156 | "version": "2.1.35",
1157 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
1158 | "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
1159 | "dependencies": {
1160 | "mime-db": "1.52.0"
1161 | },
1162 | "engines": {
1163 | "node": ">= 0.6"
1164 | }
1165 | },
1166 | "node_modules/minimatch": {
1167 | "version": "3.1.2",
1168 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
1169 | "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
1170 | "dependencies": {
1171 | "brace-expansion": "^1.1.7"
1172 | },
1173 | "engines": {
1174 | "node": "*"
1175 | }
1176 | },
1177 | "node_modules/ms": {
1178 | "version": "2.0.0",
1179 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
1180 | "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
1181 | },
1182 | "node_modules/negotiator": {
1183 | "version": "0.6.3",
1184 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
1185 | "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
1186 | "engines": {
1187 | "node": ">= 0.6"
1188 | }
1189 | },
1190 | "node_modules/nodemon": {
1191 | "version": "3.1.9",
1192 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.9.tgz",
1193 | "integrity": "sha512-hdr1oIb2p6ZSxu3PB2JWWYS7ZQ0qvaZsc3hK8DR8f02kRzc8rjYmxAIvdz+aYC+8F2IjNaB7HMcSDg8nQpJxyg==",
1194 | "dependencies": {
1195 | "chokidar": "^3.5.2",
1196 | "debug": "^4",
1197 | "ignore-by-default": "^1.0.1",
1198 | "minimatch": "^3.1.2",
1199 | "pstree.remy": "^1.1.8",
1200 | "semver": "^7.5.3",
1201 | "simple-update-notifier": "^2.0.0",
1202 | "supports-color": "^5.5.0",
1203 | "touch": "^3.1.0",
1204 | "undefsafe": "^2.0.5"
1205 | },
1206 | "bin": {
1207 | "nodemon": "bin/nodemon.js"
1208 | },
1209 | "engines": {
1210 | "node": ">=10"
1211 | },
1212 | "funding": {
1213 | "type": "opencollective",
1214 | "url": "https://opencollective.com/nodemon"
1215 | }
1216 | },
1217 | "node_modules/nodemon/node_modules/debug": {
1218 | "version": "4.4.0",
1219 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz",
1220 | "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==",
1221 | "dependencies": {
1222 | "ms": "^2.1.3"
1223 | },
1224 | "engines": {
1225 | "node": ">=6.0"
1226 | },
1227 | "peerDependenciesMeta": {
1228 | "supports-color": {
1229 | "optional": true
1230 | }
1231 | }
1232 | },
1233 | "node_modules/nodemon/node_modules/ms": {
1234 | "version": "2.1.3",
1235 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1236 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1237 | },
1238 | "node_modules/normalize-path": {
1239 | "version": "3.0.0",
1240 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
1241 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
1242 | "engines": {
1243 | "node": ">=0.10.0"
1244 | }
1245 | },
1246 | "node_modules/object-inspect": {
1247 | "version": "1.13.4",
1248 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
1249 | "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
1250 | "engines": {
1251 | "node": ">= 0.4"
1252 | },
1253 | "funding": {
1254 | "url": "https://github.com/sponsors/ljharb"
1255 | }
1256 | },
1257 | "node_modules/on-finished": {
1258 | "version": "2.4.1",
1259 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
1260 | "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
1261 | "dependencies": {
1262 | "ee-first": "1.1.1"
1263 | },
1264 | "engines": {
1265 | "node": ">= 0.8"
1266 | }
1267 | },
1268 | "node_modules/parseurl": {
1269 | "version": "1.3.3",
1270 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
1271 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
1272 | "engines": {
1273 | "node": ">= 0.8"
1274 | }
1275 | },
1276 | "node_modules/path-to-regexp": {
1277 | "version": "0.1.12",
1278 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz",
1279 | "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ=="
1280 | },
1281 | "node_modules/picomatch": {
1282 | "version": "2.3.1",
1283 | "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
1284 | "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
1285 | "engines": {
1286 | "node": ">=8.6"
1287 | },
1288 | "funding": {
1289 | "url": "https://github.com/sponsors/jonschlinkert"
1290 | }
1291 | },
1292 | "node_modules/prisma": {
1293 | "version": "6.4.1",
1294 | "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.4.1.tgz",
1295 | "integrity": "sha512-q2uJkgXnua/jj66mk6P9bX/zgYJFI/jn4Yp0aS6SPRrjH/n6VyOV7RDe1vHD0DX8Aanx4MvgmUPPoYnR6MJnPg==",
1296 | "hasInstallScript": true,
1297 | "dependencies": {
1298 | "@prisma/engines": "6.4.1",
1299 | "esbuild": ">=0.12 <1",
1300 | "esbuild-register": "3.6.0"
1301 | },
1302 | "bin": {
1303 | "prisma": "build/index.js"
1304 | },
1305 | "engines": {
1306 | "node": ">=18.18"
1307 | },
1308 | "optionalDependencies": {
1309 | "fsevents": "2.3.3"
1310 | },
1311 | "peerDependencies": {
1312 | "typescript": ">=5.1.0"
1313 | },
1314 | "peerDependenciesMeta": {
1315 | "typescript": {
1316 | "optional": true
1317 | }
1318 | }
1319 | },
1320 | "node_modules/prom-client": {
1321 | "version": "15.1.3",
1322 | "resolved": "https://registry.npmjs.org/prom-client/-/prom-client-15.1.3.tgz",
1323 | "integrity": "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g==",
1324 | "dependencies": {
1325 | "@opentelemetry/api": "^1.4.0",
1326 | "tdigest": "^0.1.1"
1327 | },
1328 | "engines": {
1329 | "node": "^16 || ^18 || >=20"
1330 | }
1331 | },
1332 | "node_modules/proxy-addr": {
1333 | "version": "2.0.7",
1334 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
1335 | "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
1336 | "dependencies": {
1337 | "forwarded": "0.2.0",
1338 | "ipaddr.js": "1.9.1"
1339 | },
1340 | "engines": {
1341 | "node": ">= 0.10"
1342 | }
1343 | },
1344 | "node_modules/pstree.remy": {
1345 | "version": "1.1.8",
1346 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
1347 | "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w=="
1348 | },
1349 | "node_modules/qs": {
1350 | "version": "6.13.0",
1351 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
1352 | "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
1353 | "dependencies": {
1354 | "side-channel": "^1.0.6"
1355 | },
1356 | "engines": {
1357 | "node": ">=0.6"
1358 | },
1359 | "funding": {
1360 | "url": "https://github.com/sponsors/ljharb"
1361 | }
1362 | },
1363 | "node_modules/range-parser": {
1364 | "version": "1.2.1",
1365 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
1366 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
1367 | "engines": {
1368 | "node": ">= 0.6"
1369 | }
1370 | },
1371 | "node_modules/raw-body": {
1372 | "version": "2.5.2",
1373 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
1374 | "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
1375 | "dependencies": {
1376 | "bytes": "3.1.2",
1377 | "http-errors": "2.0.0",
1378 | "iconv-lite": "0.4.24",
1379 | "unpipe": "1.0.0"
1380 | },
1381 | "engines": {
1382 | "node": ">= 0.8"
1383 | }
1384 | },
1385 | "node_modules/readdirp": {
1386 | "version": "3.6.0",
1387 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
1388 | "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
1389 | "dependencies": {
1390 | "picomatch": "^2.2.1"
1391 | },
1392 | "engines": {
1393 | "node": ">=8.10.0"
1394 | }
1395 | },
1396 | "node_modules/safe-buffer": {
1397 | "version": "5.2.1",
1398 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
1399 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
1400 | "funding": [
1401 | {
1402 | "type": "github",
1403 | "url": "https://github.com/sponsors/feross"
1404 | },
1405 | {
1406 | "type": "patreon",
1407 | "url": "https://www.patreon.com/feross"
1408 | },
1409 | {
1410 | "type": "consulting",
1411 | "url": "https://feross.org/support"
1412 | }
1413 | ]
1414 | },
1415 | "node_modules/safer-buffer": {
1416 | "version": "2.1.2",
1417 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
1418 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
1419 | },
1420 | "node_modules/semver": {
1421 | "version": "7.7.1",
1422 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz",
1423 | "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==",
1424 | "bin": {
1425 | "semver": "bin/semver.js"
1426 | },
1427 | "engines": {
1428 | "node": ">=10"
1429 | }
1430 | },
1431 | "node_modules/send": {
1432 | "version": "0.19.0",
1433 | "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
1434 | "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
1435 | "dependencies": {
1436 | "debug": "2.6.9",
1437 | "depd": "2.0.0",
1438 | "destroy": "1.2.0",
1439 | "encodeurl": "~1.0.2",
1440 | "escape-html": "~1.0.3",
1441 | "etag": "~1.8.1",
1442 | "fresh": "0.5.2",
1443 | "http-errors": "2.0.0",
1444 | "mime": "1.6.0",
1445 | "ms": "2.1.3",
1446 | "on-finished": "2.4.1",
1447 | "range-parser": "~1.2.1",
1448 | "statuses": "2.0.1"
1449 | },
1450 | "engines": {
1451 | "node": ">= 0.8.0"
1452 | }
1453 | },
1454 | "node_modules/send/node_modules/encodeurl": {
1455 | "version": "1.0.2",
1456 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
1457 | "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
1458 | "engines": {
1459 | "node": ">= 0.8"
1460 | }
1461 | },
1462 | "node_modules/send/node_modules/ms": {
1463 | "version": "2.1.3",
1464 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
1465 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
1466 | },
1467 | "node_modules/serve-static": {
1468 | "version": "1.16.2",
1469 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
1470 | "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
1471 | "dependencies": {
1472 | "encodeurl": "~2.0.0",
1473 | "escape-html": "~1.0.3",
1474 | "parseurl": "~1.3.3",
1475 | "send": "0.19.0"
1476 | },
1477 | "engines": {
1478 | "node": ">= 0.8.0"
1479 | }
1480 | },
1481 | "node_modules/setprototypeof": {
1482 | "version": "1.2.0",
1483 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
1484 | "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
1485 | },
1486 | "node_modules/side-channel": {
1487 | "version": "1.1.0",
1488 | "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
1489 | "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
1490 | "dependencies": {
1491 | "es-errors": "^1.3.0",
1492 | "object-inspect": "^1.13.3",
1493 | "side-channel-list": "^1.0.0",
1494 | "side-channel-map": "^1.0.1",
1495 | "side-channel-weakmap": "^1.0.2"
1496 | },
1497 | "engines": {
1498 | "node": ">= 0.4"
1499 | },
1500 | "funding": {
1501 | "url": "https://github.com/sponsors/ljharb"
1502 | }
1503 | },
1504 | "node_modules/side-channel-list": {
1505 | "version": "1.0.0",
1506 | "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
1507 | "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
1508 | "dependencies": {
1509 | "es-errors": "^1.3.0",
1510 | "object-inspect": "^1.13.3"
1511 | },
1512 | "engines": {
1513 | "node": ">= 0.4"
1514 | },
1515 | "funding": {
1516 | "url": "https://github.com/sponsors/ljharb"
1517 | }
1518 | },
1519 | "node_modules/side-channel-map": {
1520 | "version": "1.0.1",
1521 | "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
1522 | "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
1523 | "dependencies": {
1524 | "call-bound": "^1.0.2",
1525 | "es-errors": "^1.3.0",
1526 | "get-intrinsic": "^1.2.5",
1527 | "object-inspect": "^1.13.3"
1528 | },
1529 | "engines": {
1530 | "node": ">= 0.4"
1531 | },
1532 | "funding": {
1533 | "url": "https://github.com/sponsors/ljharb"
1534 | }
1535 | },
1536 | "node_modules/side-channel-weakmap": {
1537 | "version": "1.0.2",
1538 | "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
1539 | "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
1540 | "dependencies": {
1541 | "call-bound": "^1.0.2",
1542 | "es-errors": "^1.3.0",
1543 | "get-intrinsic": "^1.2.5",
1544 | "object-inspect": "^1.13.3",
1545 | "side-channel-map": "^1.0.1"
1546 | },
1547 | "engines": {
1548 | "node": ">= 0.4"
1549 | },
1550 | "funding": {
1551 | "url": "https://github.com/sponsors/ljharb"
1552 | }
1553 | },
1554 | "node_modules/simple-update-notifier": {
1555 | "version": "2.0.0",
1556 | "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
1557 | "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
1558 | "dependencies": {
1559 | "semver": "^7.5.3"
1560 | },
1561 | "engines": {
1562 | "node": ">=10"
1563 | }
1564 | },
1565 | "node_modules/statuses": {
1566 | "version": "2.0.1",
1567 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
1568 | "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
1569 | "engines": {
1570 | "node": ">= 0.8"
1571 | }
1572 | },
1573 | "node_modules/supports-color": {
1574 | "version": "5.5.0",
1575 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
1576 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
1577 | "dependencies": {
1578 | "has-flag": "^3.0.0"
1579 | },
1580 | "engines": {
1581 | "node": ">=4"
1582 | }
1583 | },
1584 | "node_modules/tdigest": {
1585 | "version": "0.1.2",
1586 | "resolved": "https://registry.npmjs.org/tdigest/-/tdigest-0.1.2.tgz",
1587 | "integrity": "sha512-+G0LLgjjo9BZX2MfdvPfH+MKLCrxlXSYec5DaPYP1fe6Iyhf0/fSmJ0bFiZ1F8BT6cGXl2LpltQptzjXKWEkKA==",
1588 | "dependencies": {
1589 | "bintrees": "1.0.2"
1590 | }
1591 | },
1592 | "node_modules/to-regex-range": {
1593 | "version": "5.0.1",
1594 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
1595 | "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
1596 | "dependencies": {
1597 | "is-number": "^7.0.0"
1598 | },
1599 | "engines": {
1600 | "node": ">=8.0"
1601 | }
1602 | },
1603 | "node_modules/toidentifier": {
1604 | "version": "1.0.1",
1605 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
1606 | "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
1607 | "engines": {
1608 | "node": ">=0.6"
1609 | }
1610 | },
1611 | "node_modules/touch": {
1612 | "version": "3.1.1",
1613 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
1614 | "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
1615 | "bin": {
1616 | "nodetouch": "bin/nodetouch.js"
1617 | }
1618 | },
1619 | "node_modules/type-is": {
1620 | "version": "1.6.18",
1621 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
1622 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
1623 | "dependencies": {
1624 | "media-typer": "0.3.0",
1625 | "mime-types": "~2.1.24"
1626 | },
1627 | "engines": {
1628 | "node": ">= 0.6"
1629 | }
1630 | },
1631 | "node_modules/undefsafe": {
1632 | "version": "2.0.5",
1633 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
1634 | "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA=="
1635 | },
1636 | "node_modules/unpipe": {
1637 | "version": "1.0.0",
1638 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
1639 | "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
1640 | "engines": {
1641 | "node": ">= 0.8"
1642 | }
1643 | },
1644 | "node_modules/utils-merge": {
1645 | "version": "1.0.1",
1646 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
1647 | "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
1648 | "engines": {
1649 | "node": ">= 0.4.0"
1650 | }
1651 | },
1652 | "node_modules/vary": {
1653 | "version": "1.1.2",
1654 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
1655 | "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
1656 | "engines": {
1657 | "node": ">= 0.8"
1658 | }
1659 | }
1660 | }
1661 | }
1662 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgres-with-prisma",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/server.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "dev": "npx prisma generate && nodemon src/server.js",
9 | "start": "npx prisma generate && nodemon src/server.js"
10 | },
11 | "keywords": [],
12 | "author": "",
13 | "license": "ISC",
14 | "dependencies": {
15 | "@prisma/client": "^6.4.1",
16 | "dotenv": "^16.4.7",
17 | "express": "^4.21.2",
18 | "nodemon": "^3.1.9",
19 | "prisma": "^6.4.1",
20 | "prom-client": "^15.1.3"
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prisma/migrations/20250223203943_init/migration.sql:
--------------------------------------------------------------------------------
1 | -- CreateTable
2 | CREATE TABLE "Book" (
3 | "id" SERIAL NOT NULL,
4 | "title" TEXT NOT NULL,
5 | "publisedDate" TIMESTAMP(3) NOT NULL,
6 |
7 | CONSTRAINT "Book_pkey" PRIMARY KEY ("id")
8 | );
9 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prisma/migrations/20250223205502_author/migration.sql:
--------------------------------------------------------------------------------
1 | /*
2 | Warnings:
3 |
4 | - Added the required column `authorId` to the `Book` table without a default value. This is not possible if the table is not empty.
5 |
6 | */
7 | -- AlterTable
8 | ALTER TABLE "Book" ADD COLUMN "authorId" INTEGER NOT NULL;
9 |
10 | -- CreateTable
11 | CREATE TABLE "Author" (
12 | "id" SERIAL NOT NULL,
13 | "name" TEXT NOT NULL,
14 |
15 | CONSTRAINT "Author_pkey" PRIMARY KEY ("id")
16 | );
17 |
18 | -- AddForeignKey
19 | ALTER TABLE "Book" ADD CONSTRAINT "Book_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "Author"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
20 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prisma/migrations/20250223214459_delete/migration.sql:
--------------------------------------------------------------------------------
1 | -- DropForeignKey
2 | ALTER TABLE "Book" DROP CONSTRAINT "Book_authorId_fkey";
3 |
4 | -- AddForeignKey
5 | ALTER TABLE "Book" ADD CONSTRAINT "Book_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "Author"("id") ON DELETE CASCADE ON UPDATE CASCADE;
6 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prisma/migrations/migration_lock.toml:
--------------------------------------------------------------------------------
1 | # Please do not edit this file manually
2 | # It should be added in your version-control system (e.g., Git)
3 | provider = "postgresql"
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prisma/schema.prisma:
--------------------------------------------------------------------------------
1 | generator client {
2 | provider = "prisma-client-js"
3 | }
4 |
5 | datasource db {
6 | provider = "postgresql"
7 | url = env("DATABASE_URL")
8 | }
9 |
10 | model Book {
11 | id Int @id @default(autoincrement())
12 | title String
13 | publisedDate DateTime
14 | authorId Int
15 | author Author @relation(fields: [authorId], references: [id], onDelete: Cascade)
16 | }
17 |
18 | model Author {
19 | id Int @id @default(autoincrement())
20 | name String
21 | books Book[]
22 | }
23 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/prometheus.yml:
--------------------------------------------------------------------------------
1 | global:
2 | scrape_interval: 5s
3 |
4 | scrape_configs:
5 | - job_name: express_prisma_api
6 | static_configs:
7 | - targets: ["express_prisma_api:3000"]
8 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/controllers/authorController.js:
--------------------------------------------------------------------------------
1 | const authorService = require("../services/authorService");
2 |
3 | exports.addAuthor = async (req, res) => {
4 | try {
5 | const { name } = req.body;
6 | const author = await authorService.addAuthor(name);
7 | res.status(201).json(author);
8 | } catch (e) {
9 | res.status(400).json({ error: e.message });
10 | }
11 | };
12 |
13 | exports.deleteAuthor = async (req, res) => {
14 | try {
15 | const deletedResult = await authorService.deleteAuthor(
16 | parseInt(req.params.id)
17 | );
18 | res
19 | .status(200)
20 | .json({
21 | message: `Author deleted with id ${req.params.id}`,
22 | deletedResult,
23 | });
24 | } catch (error) {
25 | res.status(400).json({
26 | error: error.message,
27 | });
28 | }
29 | };
30 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/controllers/bookController.js:
--------------------------------------------------------------------------------
1 | const bookService = require("../services/bookService");
2 |
3 | exports.addBook = async (req, res) => {
4 | try {
5 | const { title, publisedDate, authorId } = req.body;
6 | const book = await bookService.addBook(
7 | title,
8 | new Date(publisedDate),
9 | authorId
10 | );
11 |
12 | res.status(201).json(book);
13 | } catch (e) {
14 | res.status(400).json({ error: e.message });
15 | }
16 | };
17 |
18 | exports.getAllBooks = async (req, res) => {
19 | try {
20 | const books = await bookService.getAllBooks();
21 | res.json(books);
22 | } catch (e) {
23 | res.status(500).json({ error: e.message });
24 | }
25 | };
26 |
27 | exports.getBookById = async (req, res) => {
28 | try {
29 | const book = await bookService.getBookById(parseInt(req.params.id));
30 |
31 | if (book) {
32 | res.json(book);
33 | } else {
34 | res.status(404).json({ message: "Book not found" });
35 | }
36 | } catch (e) {
37 | res.status(500).json({ error: e.message });
38 | }
39 | };
40 |
41 | exports.updateBook = async (req, res) => {
42 | try {
43 | const { title } = req.body;
44 | const book = await bookService.updateBook(parseInt(req.params.id), title);
45 |
46 | res.json(book);
47 | } catch (e) {
48 | res.status(400).json({ error: e.message });
49 | }
50 | };
51 |
52 | exports.deleteBook = async (req, res) => {
53 | try {
54 | await bookService.deleteBook(parseInt(req.params.id));
55 | res.json({ message: `Deleted book with id ${req.params.id}` });
56 | } catch (e) {
57 | res.status(400).json({ error: e.message });
58 | }
59 | };
60 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/routes/authorRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const authorController = require("../controllers/authorController");
3 |
4 | const router = express.Router();
5 |
6 | router.post("/add-author", authorController.addAuthor);
7 | router.delete("/:id", authorController.deleteAuthor);
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/routes/bookRoutes.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const bookController = require("../controllers/bookController");
3 |
4 | const router = express.Router();
5 |
6 | router.post("/add-new-book", bookController.addBook);
7 | router.get("/get-all-books", bookController.getAllBooks);
8 | router.get("/:id", bookController.getBookById);
9 | router.put("/:id", bookController.updateBook);
10 | router.delete("/:id", bookController.deleteBook);
11 |
12 | module.exports = router;
13 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/server.js:
--------------------------------------------------------------------------------
1 | require("dotenv").config();
2 | const express = require("express");
3 | const authorRoutes = require("./routes/authorRoutes");
4 | const bookRoutes = require("./routes/bookRoutes");
5 | const promClient = require("prom-client");
6 |
7 | const app = express();
8 | app.use(express.json());
9 |
10 | const register = new promClient.Registry();
11 | promClient.collectDefaultMetrics({ register });
12 |
13 | const httpRequestsCounter = new promClient.Counter({
14 | name: "http_requests_total",
15 | help: "Total number of HTTP requests",
16 | labelNames: ["method", "route", "status"],
17 | });
18 |
19 | register.registerMetric(httpRequestsCounter);
20 |
21 | //Middleware to track API requests
22 | app.use((req, res, next) => {
23 | res.on("finish", () => {
24 | httpRequestsCounter.inc({
25 | method: req.method,
26 | route: req.path,
27 | status: res.statusCode,
28 | });
29 | });
30 |
31 | next();
32 | });
33 |
34 | //Expose the /metrics endpoint for prometheus
35 | app.get("/metrics", async (req, res) => {
36 | res.set("Content-Type", register.contentType);
37 | res.end(await register.metrics());
38 | });
39 |
40 | app.use("/api/author", authorRoutes);
41 | app.use("/api/book", bookRoutes);
42 |
43 | const PORT = process.env.PORT || 3000;
44 | app.listen(PORT, () => console.log(`Server is now running at port ${PORT}`));
45 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/services/authorService.js:
--------------------------------------------------------------------------------
1 | const { PrismaClient } = require("@prisma/client");
2 | const prisma = new PrismaClient();
3 |
4 | async function addAuthor(name) {
5 | try {
6 | const newlyCreatedAuthor = await prisma.author.create({
7 | data: {
8 | name,
9 | },
10 | });
11 |
12 | return newlyCreatedAuthor;
13 | } catch (e) {
14 | console.error(e);
15 | throw e;
16 | }
17 | }
18 |
19 | async function deleteAuthor(id) {
20 | try {
21 | const deletedAuthor = await prisma.author.delete({
22 | where: { id },
23 | include: { books: true },
24 | });
25 |
26 | return deletedAuthor;
27 | } catch (error) {
28 | throw new Error(error.message);
29 | }
30 | }
31 |
32 | module.exports = { addAuthor, deleteAuthor };
33 |
--------------------------------------------------------------------------------
/postgres/postgres-with-prisma/src/services/bookService.js:
--------------------------------------------------------------------------------
1 | const { PrismaClient } = require("@prisma/client");
2 |
3 | const prisma = new PrismaClient();
4 |
5 | async function addBook(title, publisedDate, authorId) {
6 | try {
7 | const newlyCreatedBook = await prisma.book.create({
8 | data: {
9 | title,
10 | publisedDate,
11 | author: {
12 | connect: { id: authorId },
13 | },
14 | },
15 | include: { author: true },
16 | });
17 |
18 | return newlyCreatedBook;
19 | } catch (e) {
20 | console.error(e);
21 | throw e;
22 | }
23 | }
24 |
25 | async function getAllBooks() {
26 | try {
27 | const books = await prisma.book.findMany({
28 | include: { author: true },
29 | });
30 |
31 | return books;
32 | } catch (e) {
33 | throw e;
34 | }
35 | }
36 |
37 | async function getBookById(id) {
38 | try {
39 | const book = await prisma.book.findUnique({
40 | where: { id },
41 | include: { author: true },
42 | });
43 |
44 | if (!book) {
45 | throw new Error(`Book with id ${id} not found`);
46 | }
47 |
48 | return book;
49 | } catch (e) {
50 | throw e;
51 | }
52 | }
53 |
54 | async function updateBook(id, newTitle) {
55 | try {
56 | // const book = await prisma.book.findUnique({
57 | // where: { id },
58 | // include: { author: true },
59 | // });
60 |
61 | // if (!book) {
62 | // throw new Error(`Book with id ${id} not found`);
63 | // }
64 | // const updatedBook = await prisma.book.update({
65 | // where: { id },
66 | // data: {
67 | // title: newTitle,
68 | // },
69 | // include: {
70 | // author: true,
71 | // },
72 | // });
73 |
74 | // return updatedBook;
75 |
76 | //using transactions
77 | const updatedBook = await prisma.$transaction(async (prisma) => {
78 | const book = await prisma.book.findUnique({ where: { id } });
79 | if (!book) {
80 | throw new Error(`Book with id ${id} not found`);
81 | }
82 |
83 | return prisma.book.update({
84 | where: { id },
85 | data: {
86 | title: newTitle,
87 | },
88 | include: {
89 | author: true,
90 | },
91 | });
92 | });
93 |
94 | return updatedBook;
95 | } catch (e) {
96 | throw e;
97 | }
98 | }
99 |
100 | async function deleteBook(id) {
101 | try {
102 | const deletedBook = await prisma.book.delete({
103 | where: { id },
104 | include: { author: true },
105 | });
106 |
107 | return deletedBook;
108 | } catch (e) {
109 | throw error;
110 | }
111 | }
112 |
113 | module.exports = { addBook, getAllBooks, getBookById, updateBook, deleteBook };
114 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgress-concepts",
3 | "version": "1.0.0",
4 | "lockfileVersion": 3,
5 | "requires": true,
6 | "packages": {
7 | "": {
8 | "name": "postgress-concepts",
9 | "version": "1.0.0",
10 | "license": "ISC",
11 | "dependencies": {
12 | "dotenv": "^16.4.7",
13 | "pg": "^8.13.3"
14 | }
15 | },
16 | "node_modules/dotenv": {
17 | "version": "16.4.7",
18 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.7.tgz",
19 | "integrity": "sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==",
20 | "engines": {
21 | "node": ">=12"
22 | },
23 | "funding": {
24 | "url": "https://dotenvx.com"
25 | }
26 | },
27 | "node_modules/pg": {
28 | "version": "8.13.3",
29 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.13.3.tgz",
30 | "integrity": "sha512-P6tPt9jXbL9HVu/SSRERNYaYG++MjnscnegFh9pPHihfoBSujsrka0hyuymMzeJKFWrcG8wvCKy8rCe8e5nDUQ==",
31 | "dependencies": {
32 | "pg-connection-string": "^2.7.0",
33 | "pg-pool": "^3.7.1",
34 | "pg-protocol": "^1.7.1",
35 | "pg-types": "^2.1.0",
36 | "pgpass": "1.x"
37 | },
38 | "engines": {
39 | "node": ">= 8.0.0"
40 | },
41 | "optionalDependencies": {
42 | "pg-cloudflare": "^1.1.1"
43 | },
44 | "peerDependencies": {
45 | "pg-native": ">=3.0.1"
46 | },
47 | "peerDependenciesMeta": {
48 | "pg-native": {
49 | "optional": true
50 | }
51 | }
52 | },
53 | "node_modules/pg-cloudflare": {
54 | "version": "1.1.1",
55 | "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz",
56 | "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==",
57 | "optional": true
58 | },
59 | "node_modules/pg-connection-string": {
60 | "version": "2.7.0",
61 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.7.0.tgz",
62 | "integrity": "sha512-PI2W9mv53rXJQEOb8xNR8lH7Hr+EKa6oJa38zsK0S/ky2er16ios1wLKhZyxzD7jUReiWokc9WK5nxSnC7W1TA=="
63 | },
64 | "node_modules/pg-int8": {
65 | "version": "1.0.1",
66 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz",
67 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==",
68 | "engines": {
69 | "node": ">=4.0.0"
70 | }
71 | },
72 | "node_modules/pg-pool": {
73 | "version": "3.7.1",
74 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.7.1.tgz",
75 | "integrity": "sha512-xIOsFoh7Vdhojas6q3596mXFsR8nwBQBXX5JiV7p9buEVAGqYL4yFzclON5P9vFrpu1u7Zwl2oriyDa89n0wbw==",
76 | "peerDependencies": {
77 | "pg": ">=8.0"
78 | }
79 | },
80 | "node_modules/pg-protocol": {
81 | "version": "1.7.1",
82 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.7.1.tgz",
83 | "integrity": "sha512-gjTHWGYWsEgy9MsY0Gp6ZJxV24IjDqdpTW7Eh0x+WfJLFsm/TJx1MzL6T0D88mBvkpxotCQ6TwW6N+Kko7lhgQ=="
84 | },
85 | "node_modules/pg-types": {
86 | "version": "2.2.0",
87 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz",
88 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==",
89 | "dependencies": {
90 | "pg-int8": "1.0.1",
91 | "postgres-array": "~2.0.0",
92 | "postgres-bytea": "~1.0.0",
93 | "postgres-date": "~1.0.4",
94 | "postgres-interval": "^1.1.0"
95 | },
96 | "engines": {
97 | "node": ">=4"
98 | }
99 | },
100 | "node_modules/pgpass": {
101 | "version": "1.0.5",
102 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
103 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
104 | "dependencies": {
105 | "split2": "^4.1.0"
106 | }
107 | },
108 | "node_modules/postgres-array": {
109 | "version": "2.0.0",
110 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz",
111 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==",
112 | "engines": {
113 | "node": ">=4"
114 | }
115 | },
116 | "node_modules/postgres-bytea": {
117 | "version": "1.0.0",
118 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz",
119 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==",
120 | "engines": {
121 | "node": ">=0.10.0"
122 | }
123 | },
124 | "node_modules/postgres-date": {
125 | "version": "1.0.7",
126 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
127 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
128 | "engines": {
129 | "node": ">=0.10.0"
130 | }
131 | },
132 | "node_modules/postgres-interval": {
133 | "version": "1.2.0",
134 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz",
135 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==",
136 | "dependencies": {
137 | "xtend": "^4.0.0"
138 | },
139 | "engines": {
140 | "node": ">=0.10.0"
141 | }
142 | },
143 | "node_modules/split2": {
144 | "version": "4.2.0",
145 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
146 | "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
147 | "engines": {
148 | "node": ">= 10.x"
149 | }
150 | },
151 | "node_modules/xtend": {
152 | "version": "4.0.2",
153 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
154 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
155 | "engines": {
156 | "node": ">=0.4"
157 | }
158 | }
159 | }
160 | }
161 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "postgress-concepts",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "src/main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "start": "node src/main.js"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "dotenv": "^16.4.7",
15 | "pg": "^8.13.3"
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/concepts/aggregation.js:
--------------------------------------------------------------------------------
1 | const db = require("../db/db");
2 |
3 | async function countPostsByUser() {
4 | const countPostsByUserQuery = `
5 | SELECT users.username, COUNT(posts.id) as post_count
6 | FROM users
7 | LEFT JOIN posts ON users.id = posts.user_id
8 | GROUP BY users.id, users.username
9 | `;
10 |
11 | try {
12 | const res = await db.query(countPostsByUserQuery);
13 | return res.rows;
14 | } catch (e) {
15 | console.error(e);
16 | }
17 | }
18 |
19 | async function averagePostsPerUser() {
20 | const averagePostsPerUserQuery = `
21 | SELECT AVG(post_count) as average_posts
22 | FROM(
23 | SELECT COUNT(posts.id) as post_count
24 | FROM users
25 | LEFT JOIN posts ON users.id = posts.user_id
26 | GROUP BY users.id
27 |
28 | ) as user_per_counts
29 | `;
30 | try {
31 | const res = await db.query(averagePostsPerUserQuery);
32 | return res.rows;
33 | } catch (e) {
34 | console.error(e);
35 | }
36 | }
37 |
38 | module.exports = {
39 | countPostsByUser,
40 | averagePostsPerUser,
41 | };
42 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/concepts/basic-queries.js:
--------------------------------------------------------------------------------
1 | const db = require("../db/db");
2 |
3 | async function createUsersTable() {
4 | const createTableQuery = `
5 | CREATE TABLE IF NOT EXISTS users(
6 | id SERIAL PRIMARY KEY,
7 | username VARCHAR(50) UNIQUE NOT NULL,
8 | email VARCHAR(255) UNIQUE NOT NULL,
9 | created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
10 | )
11 | `;
12 |
13 | try {
14 | await db.query(createTableQuery);
15 | console.log("Users table created successfully");
16 | } catch (error) {
17 | console.error("Error while creating users table", error);
18 | }
19 | }
20 |
21 | async function insertUser(username, email) {
22 | const inserUserQuery = `
23 | INSERT INTO users (username, email)
24 | VALUES ($1, $2)
25 | RETURNING *
26 | `;
27 |
28 | try {
29 | const res = await db.query(inserUserQuery, [username, email]);
30 | console.log("User inserted successfully", res.rows[0]);
31 |
32 | return res.rows[0];
33 | } catch (error) {
34 | console.error("Error while creating users table", error);
35 | }
36 | }
37 |
38 | async function fetchAllUsers() {
39 | const getAllUsersFromUsersTable = "SELECT * FROM users";
40 |
41 | try {
42 | const res = await db.query(getAllUsersFromUsersTable);
43 | console.log("Fetched all users", res);
44 |
45 | return res.rows;
46 | } catch (error) {
47 | console.error("Error", error);
48 | }
49 | }
50 |
51 | // update -> sangam@gmail.com to raj@gmail.com where user name is Sangam Mukherjee
52 |
53 | async function updateUserInfo(username, newEmail) {
54 | const updateUserQuery = `
55 | UPDATE users
56 | SET email = $2
57 | WHERE username = $1
58 | RETURNING *
59 | `;
60 |
61 | try {
62 | const res = await db.query(updateUserQuery, [username, newEmail]);
63 |
64 | if (res.rows.length > 0) {
65 | console.log("User updated successfully!", res.rows[0]);
66 | return res.rows[0];
67 | } else {
68 | console.log("No user found with given username");
69 | return null;
70 | }
71 | } catch (error) {
72 | console.error("Error while creating users table", error);
73 | }
74 | }
75 |
76 | async function deleteInfo(username) {
77 | const deleteQuery = `
78 | DELETE FROM users
79 | WHERE username = $1
80 | RETURNING *
81 | `;
82 | try {
83 | const res = await db.query(deleteQuery, [username]);
84 |
85 | if (res.rows.length > 0) {
86 | console.log("User deleted successfully!", res.rows[0]);
87 | return res.rows[0];
88 | } else {
89 | console.log("No user found with given username");
90 | return null;
91 | }
92 | } catch (error) {
93 | console.error("Error while creating users table", error);
94 | }
95 | }
96 |
97 | module.exports = {
98 | createUsersTable,
99 | insertUser,
100 | fetchAllUsers,
101 | updateUserInfo,
102 | deleteInfo,
103 | };
104 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/concepts/filtering-sorting.js:
--------------------------------------------------------------------------------
1 | const db = require("../db/db");
2 |
3 | //WHERE clause
4 |
5 | async function getUsersWhere(condition) {
6 | const getUsersQuery = `
7 | SELECT * FROM users
8 | WHERE ${condition}
9 | `;
10 |
11 | try {
12 | const res = await db.query(getUsersQuery);
13 | return res.rows;
14 | } catch (e) {
15 | console.error(e);
16 | }
17 | }
18 |
19 | async function getSortedUsers(column, order = "ASC") {
20 | const getSortedUsersQuery = `
21 | SELECT * FROM users
22 | ORDER BY ${column} ${order}
23 | `;
24 |
25 | try {
26 | const result = await db.query(getSortedUsersQuery);
27 |
28 | return result.rows;
29 | } catch (e) {
30 | console.error(e);
31 | }
32 | }
33 |
34 | async function getPaginatedUsers(limit, offset) {
35 | const getPaginatedQuery = `
36 | SELECT * FROM users
37 | LIMIT $1 OFFSET $2
38 | `;
39 |
40 | try {
41 | const result = await db.query(getPaginatedQuery, [limit, offset]);
42 |
43 | return result.rows;
44 | } catch (e) {
45 | console.error(e);
46 | }
47 | }
48 |
49 | module.exports = { getUsersWhere, getSortedUsers, getPaginatedUsers };
50 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/concepts/joins.js:
--------------------------------------------------------------------------------
1 | const db = require("../db/db");
2 |
3 | // -> inner join returns only the rows where thers is a match in both tables
4 |
5 | async function getUsersWithPosts() {
6 | const getUsersWithPostsQuery = `
7 | SELECT users.id, users.username, posts.title
8 | FROM users
9 | INNER JOIN posts ON users.id = posts.user_id
10 | `;
11 |
12 | try {
13 | const res = await db.query(getUsersWithPostsQuery);
14 | return res.rows;
15 | } catch (e) {
16 | console.error(e);
17 | }
18 | }
19 |
20 | async function getAllUsersAndTheirPosts() {
21 | const getAllUsersAndTheirPostsQuery = `
22 | SELECT users.id, users.username, posts.title
23 | FROM users
24 | LEFT JOIN posts ON users.id = posts.user_id
25 | `;
26 | try {
27 | const res = await db.query(getAllUsersAndTheirPostsQuery);
28 | return res.rows;
29 | } catch (e) {
30 | console.error(e);
31 | }
32 | }
33 |
34 | module.exports = { getUsersWithPosts, getAllUsersAndTheirPosts };
35 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/concepts/relationships.js:
--------------------------------------------------------------------------------
1 | const db = require("../db/db");
2 |
3 | async function createPostsTable() {
4 | const createTableQuery = `
5 | CREATE TABLE IF NOT EXISTS posts(
6 | id SERIAL PRIMARY KEY,
7 | title VARCHAR(255) NOT NULL,
8 | content TEXT,
9 | user_id INTEGER REFERENCES users(id) ON DELETE CASCADE,
10 | created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
11 | )
12 | `;
13 |
14 | try {
15 | await db.query(createTableQuery);
16 | console.log("Posts table created successfully!");
17 | } catch (e) {
18 | console.error(e);
19 | }
20 | }
21 |
22 | async function insertNewPost(title, content, userId) {
23 | const insertPostQuery = `
24 | INSERT INTO posts (title, content, user_id)
25 | VALUES ($1, $2, $3)
26 | RETURNING *
27 | `;
28 |
29 | try {
30 | const result = await db.query(insertPostQuery, [title, content, userId]);
31 |
32 | return result.rows[0];
33 | } catch (e) {}
34 | }
35 |
36 | module.exports = {
37 | createPostsTable,
38 | insertNewPost,
39 | };
40 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/db/db.js:
--------------------------------------------------------------------------------
1 | const { Pool } = require("pg");
2 |
3 | require("dotenv").config();
4 |
5 | //create a new pool instance to manage database connections
6 | // -> postgre -> :// -> [user] -> [password] -> @ -> host:port -> [database]
7 |
8 | const pool = new Pool({
9 | connectionString: process.env.DATABASE_URL,
10 | });
11 |
12 | async function query(text, params) {
13 | const start = Date.now();
14 |
15 | try {
16 | const result = await pool.query(text, params);
17 |
18 | //execute the time ->
19 | const duration = Date.now() - start;
20 |
21 | console.log(
22 | `Executed query: , ${{ text, duration, rows: result.rowCount }}`
23 | );
24 |
25 | return result;
26 | } catch (e) {
27 | console.error(e);
28 |
29 | throw e;
30 | }
31 | }
32 |
33 | module.exports = { query };
34 |
--------------------------------------------------------------------------------
/postgres/postgress-concepts/src/main.js:
--------------------------------------------------------------------------------
1 | const {
2 | countPostsByUser,
3 | averagePostsPerUser,
4 | } = require("./concepts/aggregation");
5 | const {
6 | insertUser,
7 | createUsersTable,
8 | fetchAllUsers,
9 | updateUserInfo,
10 | deleteInfo,
11 | } = require("./concepts/basic-queries");
12 | const {
13 | getUsersWhere,
14 | getSortedUsers,
15 | getPaginatedUsers,
16 | } = require("./concepts/filtering-sorting");
17 | const {
18 | getUsersWithPosts,
19 | getAllUsersAndTheirPosts,
20 | } = require("./concepts/joins");
21 | const { createPostsTable, insertNewPost } = require("./concepts/relationships");
22 |
23 | //test basic queries
24 | async function testBasicQueries() {
25 | try {
26 | await createUsersTable();
27 | // Insert new users
28 | await insertUser("Zxy", "zxy@gmail.com");
29 | await insertUser("John Doe", "john@gmail.com");
30 | await insertUser("Travis Mclaren", "travis123@gmail.com");
31 | await insertUser("Jennifer Lopez", "jennifer@gmail.com");
32 | await insertUser("Zayn Malik", "zaynmalik@gmail.com");
33 | console.log("All users");
34 | const allUsers = await fetchAllUsers();
35 | console.log(allUsers);
36 | const updatedUser = await updateUserInfo(
37 | "Sangam Mukherjee",
38 | "raja@gmail.com"
39 | );
40 | console.log(updatedUser);
41 |
42 | const deletedUser = await deleteInfo("Sangam Mukherjee");
43 | console.log(deletedUser);
44 | } catch (e) {
45 | console.error("Error", error);
46 | }
47 | }
48 |
49 | async function testFilterAndSortQueries() {
50 | try {
51 | //get users with a username whose username starting with z
52 | // const zFilteredUsers = await getUsersWhere("username LIKE 'Z%'");
53 | // console.log(zFilteredUsers);
54 |
55 | // const sortedUsers = await getSortedUsers("created_at", "ASC");
56 | // console.log(sortedUsers);
57 |
58 | const paginatedUsers = await getPaginatedUsers(2, 1);
59 | console.log("paginatedUsers", paginatedUsers);
60 | } catch (e) {
61 | console.error("Error", error);
62 | }
63 | }
64 |
65 | async function testRelationshipQueries() {
66 | try {
67 | // await createPostsTable();
68 |
69 | await insertNewPost("Second post", "This is my second post", 3);
70 | await insertNewPost("Third post", "Tecond post", 4);
71 | } catch (e) {
72 | console.error("Error", error);
73 | }
74 | }
75 |
76 | async function testJoinQueries() {
77 | try {
78 | // const usersWithPosts = await getUsersWithPosts();
79 |
80 | // console.log(usersWithPosts);
81 |
82 | const allUsersWithAllPosts = await getAllUsersAndTheirPosts();
83 | console.log(allUsersWithAllPosts);
84 | } catch (e) {
85 | console.error(e);
86 | }
87 | }
88 |
89 | async function testAggregateQuerise() {
90 | try {
91 | // const postCount = await countPostsByUser();
92 | // console.log(postCount);
93 |
94 | const averagePostsPerUserInfo = await averagePostsPerUser();
95 | console.log(averagePostsPerUserInfo);
96 | } catch (e) {
97 | console.error(e);
98 | }
99 | }
100 |
101 | async function testAllQueries() {
102 | // await testBasicQueries();
103 | // await testFilterAndSortQueries();
104 | // await testRelationshipQueries();
105 |
106 | // await testJoinQueries();
107 | await testAggregateQuerise();
108 | }
109 |
110 | testAllQueries();
111 |
--------------------------------------------------------------------------------