renaming and docs

This commit is contained in:
Anika Raemer 2025-10-04 18:16:49 +02:00
parent b1b714f44e
commit 7e831cfb64
14 changed files with 86 additions and 32 deletions

View file

@ -11,9 +11,16 @@ const __dirname = dirname(__filename);
dotenv.config();
/**
* Load config
*/
const { DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE, NODE_ENV } =
process.env;
/**
* Configures data source
*/
export const AppDataSource = new DataSource({
type: "postgres",
host: DB_HOST,

View file

@ -1,5 +1,5 @@
import { Router } from "express";
import { AuthController } from "../controllers/AuthController.js";
import { AuthHandler } from "../handlers/AuthHandler.js";
import { UserRepository } from "../repositories/UserRepository.js";
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
import {
@ -14,8 +14,13 @@ export const authBasicRoute = "/auth"
const router = Router();
const userRepository = new UserRepository();
const mapper = new UserDtoEntityMapper();
const authController = new AuthController(userRepository, mapper);
const authController = new AuthHandler(userRepository, mapper);
/**
* Login using username and password
* Consumes LoginRequestDto
* Responds with LoginResponseDto
*/
router.post("/login", async (req, res) => {
console.log("login point called")
try {

View file

@ -1,7 +1,7 @@
import { Router } from "express";
import { asyncHandler } from "../utils/asyncHandler.js";
import { RecipeRepository } from "../repositories/RecipeRepository.js";
import { CompactRecipeController } from "../controllers/CompactRecipeController.js";
import { CompactRecipeHandler } from "../handlers/CompactRecipeHandler.js";
import { CompactRecipeDtoEntityMapper } from "../mappers/CompactRecipeDtoEntityMapper.js";
/**
@ -12,9 +12,10 @@ const router = Router();
// Inject repo + mapper here
const recipeRepository = new RecipeRepository();
const compactRecipeMapper = new CompactRecipeDtoEntityMapper();
const compactRecipeController = new CompactRecipeController(recipeRepository, compactRecipeMapper);
const compactRecipeController = new CompactRecipeHandler(recipeRepository, compactRecipeMapper);
/**
* Load header data of all recipes
* Responds with a list of CompactRecipeDtos
*/
router.get(
"/",

View file

@ -1,7 +1,7 @@
import { Router } from "express";
import { RecipeRepository } from "../repositories/RecipeRepository.js";
import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.js";
import { RecipeController } from "../controllers/RecipeController.js";
import { RecipeHandler } from "../handlers/RecipeHandler.js";
import { asyncHandler } from "../utils/asyncHandler.js";
import { RecipeDto } from "../dtos/RecipeDto.js";
import { RecipeIngredientDtoEntityMapper } from "../mappers/RecipeIngredientDtoEntityMapper.js";
@ -20,10 +20,12 @@ const recipeIngredientMapper = new RecipeIngredientDtoEntityMapper();
const recipeIngredientGroupMapper = new RecipeIngredientGroupDtoEntityMapper(recipeIngredientMapper);
const recipeInstructionStepMapper = new RecipeInstructionStepDtoEntityMapper();
const recipeMapper = new RecipeDtoEntityMapper(recipeInstructionStepMapper, recipeIngredientGroupMapper);
const recipeController = new RecipeController(recipeRepository, recipeMapper);
const recipeController = new RecipeHandler(recipeRepository, recipeMapper);
/**
* Create new recipe
* Consumes: RecipeDto
* Responds with RecipeDto
*/
router.post(
"/",
@ -34,6 +36,10 @@ router.post(
})
);
/**
* Load recipe by id
* Responds with RecipeDto
*/
router.get(
"/:id",
asyncHandler(async(req, res) => {
@ -43,6 +49,12 @@ router.get(
})
);
/**
* Saves existing recipe
* Also handles changes to instructions steps and ingredient (groups)
* Consumes: RecipeDto
* Responds with RecipeDto
*/
router.put(
"/:id",
asyncHandler(async(req, res) =>{

View file

@ -1,5 +1,5 @@
import { Router } from "express";
import { UserController } from "../controllers/UserController.js";
import { UserHandler } from "../handlers/UserHandler.js";
import { CreateUserRequestDto } from "../dtos/CreateUserRequestDto.js";
import { UserRepository } from "../repositories/UserRepository.js";
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
@ -13,10 +13,12 @@ const router = Router();
// Inject repo + mapper here
const userRepository = new UserRepository();
const userMapper = new UserDtoEntityMapper();
const userController = new UserController(userRepository, userMapper);
const userController = new UserHandler(userRepository, userMapper);
/**
* Create a new user
* Consumes CreateUserRequestDto
* Responds with UserDto
*/
router.post(
"/",
@ -29,6 +31,7 @@ router.post(
/**
* Get user data for current user
* Responds with UserDto
*/
router.get("/me",
asyncHandler(async (req, res) => {

View file

@ -4,6 +4,9 @@ import {
UpdateDateColumn,
} from "typeorm";
/**
* Abstract entity containing basic fields that all entities have in common
*/
export abstract class AbstractEntity {
@PrimaryGeneratedColumn("uuid")
id?: string;

View file

@ -1,7 +1,9 @@
import { Entity, Column } from "typeorm";
import { AbstractEntity } from "./AbstractEntity.js";
// @todo Add migration to update table
/**
* Entity describing a user
*/
@Entity({ name: "user" })
export class UserEntity extends AbstractEntity {
@Column({ nullable: false, name: "user_name" })

View file

@ -9,7 +9,7 @@ import { LoginRequestDto } from "../dtos/LoginRequestDto.js";
* Controller responsible for authentication, e.g., login or issueing a token with extended
* lifetime
*/
export class AuthController {
export class AuthHandler {
constructor(
private userRepository: UserRepository,
private mapper: UserDtoEntityMapper

View file

@ -6,7 +6,7 @@ import { RecipeRepository } from "../repositories/RecipeRepository.js";
/**
* Responsible for loading recipe header data
*/
export class CompactRecipeController {
export class CompactRecipeHandler {
constructor(
private repository: RecipeRepository,
private mapper: CompactRecipeDtoEntityMapper

View file

@ -5,13 +5,11 @@ import { NotFoundError, ValidationError } from "../errors/httpErrors.js";
import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js";
import { RecipeIngredientGroupDto } from "../dtos/RecipeIngredientGroupDto.js";
import { RecipeIngredientDto } from "../dtos/RecipeIngredientDto.js";
import { Entity } from "typeorm";
import { RecipeEntity } from "../entities/RecipeEntity.js";
/**
* Controls all recipe specific actions
*/
export class RecipeController {
export class RecipeHandler {
constructor(
private recipeRepository: RecipeRepository,
private mapper: RecipeDtoEntityMapper

View file

@ -9,7 +9,7 @@ import { UUID } from "crypto";
/**
* Controls all user specific actions
*/
export class UserController {
export class UserHandler {
constructor(
private userRepository: UserRepository,
private mapper: UserDtoEntityMapper

View file

@ -25,12 +25,16 @@ export abstract class AbstractDtoEntityMapper<
return entity;
}
// Abstract methods to be implemented by subclasses
abstract toDto(entity: E): D;
abstract toEntity(dto: D): E;
abstract mergeDtoIntoEntity(dto: D, entity: E): E;
abstract createNewEntity() : E;
/**
* Merge entity list with changes contained in DTO list
* @param dtos List of dtos
* @param entities List of entities
* @returns Merged list
*
* elements no longer contained in the dto list will be removed from the entity list
* new elements will be mapped to entity and added to the entity list
* existing elements will be updated
*/
mergeDtoListIntoEntityList(dtos: D[], entities: E[]) : E[]{
const updatedEntities: E[] = [];
const existingMap = new Map(entities?.map(e => [e.id, e]) ?? []);
@ -49,4 +53,29 @@ export abstract class AbstractDtoEntityMapper<
return updatedEntities;
}
// Abstract methods to be implemented by subclasses
/**
* Maps an entity to DTO
* @param entity Entity that is mapped to DTO
*/
abstract toDto(entity: E): D;
/**
* Maps a DTO to entity
* @param dto DTO to map to entity
*/
abstract toEntity(dto: D): E;
/**
* Merge changes in DTO into entity
* @param dto Dto containing changes
* @param entity existing entity
*
* Used for merging user changes (DTO) into the existing entity (database).
*/
abstract mergeDtoIntoEntity(dto: D, entity: E): E;
/**
* Defines how to create a new entity. Required by mergeDtoListIntoEntityList
* to add new elements to the list
*/
abstract createNewEntity() : E;
}

View file

@ -17,11 +17,11 @@ export class CompactRecipeDtoEntityMapper extends AbstractDtoEntityMapper<Recipe
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
}
mergeDtoIntoEntity(dto: CompactRecipeDto, entity: RecipeEntity): RecipeEntity {
createNewEntity() : RecipeEntity {
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
}
createNewEntity() : RecipeEntity {
mergeDtoIntoEntity(dto: CompactRecipeDto, entity: RecipeEntity): RecipeEntity {
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
}

View file

@ -2,6 +2,9 @@ import { Repository, DeepPartial } from "typeorm";
import { AppDataSource } from "../data-source.js";
import { AbstractEntity } from "../entities/AbstractEntity.js";
/**
* Basic methods for saving, loading and deleting data
*/
export abstract class AbstractRepository<T extends AbstractEntity> {
protected repo: Repository<T>;
@ -22,15 +25,6 @@ export abstract class AbstractRepository<T extends AbstractEntity> {
return this.repo.save(entity);
}
/* async update(id: string, partialData: DeepPartial<T>): Promise<T> {
await this.repo.update(id as any, partialData);
const updated = await this.findById(id);
if (!updated) {
throw new Error("Entity not found after update");
}
return updated;
} */
async delete(id: string): Promise<void> {
await this.repo.delete(id as any);
}