From b031d83a7d0a5d25b9c22e6c571e75c2ab75e4e6 Mon Sep 17 00:00:00 2001 From: Dave Smith-Hayes Date: Thu, 4 Apr 2024 22:13:32 -0400 Subject: [PATCH] Add a database connection, get the bcrypt library installed, implement a simple user repository. --- app/bun.lockb | Bin 31675 -> 54447 bytes app/package.json | 4 +- app/src/domain/entity.ts | 19 ++++++ app/src/domain/repository.ts | 10 +-- app/src/domain/repository/user-repository.ts | 63 +++++++++++++++++++ app/src/infrastructure/database-pool.ts | 10 +++ app/src/models/image.ts | 2 +- app/src/server.ts | 6 +- 8 files changed, 107 insertions(+), 7 deletions(-) create mode 100644 app/src/domain/entity.ts create mode 100644 app/src/domain/repository/user-repository.ts create mode 100644 app/src/infrastructure/database-pool.ts diff --git a/app/bun.lockb b/app/bun.lockb index 68b9299c11a65afeff5482dc5c2ccbdea9d2ec96..0ba25ec771d594e6515963e96509b5dbba2b4b6d 100755 GIT binary patch delta 19413 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 N3BR*;_nr7C>_5Lv6{Y|H diff --git a/app/package.json b/app/package.json index 0b8f5b6..b07ebb0 100644 --- a/app/package.json +++ b/app/package.json @@ -10,6 +10,8 @@ }, "dependencies": { "@types/express": "^4.17.21", - "express": "^4.19.2" + "bcrypt": "^5.1.1", + "express": "^4.19.2", + "mariadb": "^3.3.0" } } \ No newline at end of file diff --git a/app/src/domain/entity.ts b/app/src/domain/entity.ts new file mode 100644 index 0000000..e4c64cb --- /dev/null +++ b/app/src/domain/entity.ts @@ -0,0 +1,19 @@ +export type EntityId = number|string; + +export class Entity { + protected readonly id: EntityId; + protected model: T; + + public constructor(id: EntityId, model: T) { + this.id = id; + this.model = model; + } + + public getId(): EntityId { + return this.id; + } + + public getModel(): T { + return this.model; + } +} diff --git a/app/src/domain/repository.ts b/app/src/domain/repository.ts index 61fdf82..7d0ce9c 100644 --- a/app/src/domain/repository.ts +++ b/app/src/domain/repository.ts @@ -1,7 +1,9 @@ +import { Entity, type EntityId } from '@slovo/domain/entity'; + export interface Repository { - get(id: any): Promise; - save(model: T): Promise; - update(model: T): Promise; - delete(model: T): Promise; + get(id: EntityId): Promise>; + save(model: T): Promise>; + update(model: Entity): Promise>; + delete(model: Entity): Promise; } diff --git a/app/src/domain/repository/user-repository.ts b/app/src/domain/repository/user-repository.ts new file mode 100644 index 0000000..9bb9f81 --- /dev/null +++ b/app/src/domain/repository/user-repository.ts @@ -0,0 +1,63 @@ +import { type Repository } from '@slovo/domain/repository'; +import { Entity, type EntityId } from '@slovo/domain/entity'; +import { type User } from '@slovo/models/user'; +import { type PoolConnection } from 'mariadb'; +import connectionPool from '@slovo/infrastructure/database-pool'; + +export class UserRepository implements Repository { + public async get(id: EntityId): Promise> { + const conn: PoolConnection = await connectionPool.getConnection(); + + const query = `SELECT * FROM users WHERE id = ?`; + const rows = await conn.query(query, [ id ]); + + if (!rows.length) { + throw Error("Unable to find User"); + } + + const row = rows.shift(); + + const user: User = { + name: row.name, + email: row.email, + password: row.password + }; + + await conn.release(); + return new Entity(id, user); + } + + public async save(user: User): Promise> { + const conn: PoolConnection = await connectionPool.getConnection(); + + const query = `INSERT INTO users (name, email, password) VALUES (?, ?, ?)`; + const rows = await conn.query(query, [ user.name, user.email, user.password ]); + + if (!rows.length) { + throw Error("Unable to create User"); + } + + await conn.release(); + return new Entity(rows.insertId, user); + } + + public async update(user: Entity): Promise> { + const conn: PoolConnection = await connectionPool.getConnection(); + + const query = `UPDATE user SET name = ?, email = ?, password = ? WHERE id = ?`; + const results = await conn.query(query, [ + user.getModel().name, + user.getModel().email, + user.getModel().password, + user.getId() + ]); + + await conn.release(); + } + + public async delete(user: Entity): Promise { + const conn: PoolConnection = await connectionPool.getConnection(); + + await conn.release(); + } +} diff --git a/app/src/infrastructure/database-pool.ts b/app/src/infrastructure/database-pool.ts new file mode 100644 index 0000000..d7b96e8 --- /dev/null +++ b/app/src/infrastructure/database-pool.ts @@ -0,0 +1,10 @@ +import { createPool } from 'mariadb'; + +const connectionPool = createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_SCHEMA +}); + +export default connectionPool; diff --git a/app/src/models/image.ts b/app/src/models/image.ts index 47a8147..2426101 100644 --- a/app/src/models/image.ts +++ b/app/src/models/image.ts @@ -1,6 +1,6 @@ export type Image = { url: URL, - title: string, + title?: string, width: number, height: number, }; diff --git a/app/src/server.ts b/app/src/server.ts index 6c55812..ba4a8b8 100644 --- a/app/src/server.ts +++ b/app/src/server.ts @@ -1,4 +1,8 @@ -import express, { Express, type Request, type Response } from "express"; +import express, { + type Express, + type Request, + type Response +} from "express"; const server: Express = express();