renaming and docs
This commit is contained in:
parent
b1b714f44e
commit
7e831cfb64
14 changed files with 86 additions and 32 deletions
|
|
@ -11,9 +11,16 @@ const __dirname = dirname(__filename);
|
||||||
|
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load config
|
||||||
|
*/
|
||||||
const { DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE, NODE_ENV } =
|
const { DB_HOST, DB_PORT, DB_USERNAME, DB_PASSWORD, DB_DATABASE, NODE_ENV } =
|
||||||
process.env;
|
process.env;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures data source
|
||||||
|
*/
|
||||||
|
|
||||||
export const AppDataSource = new DataSource({
|
export const AppDataSource = new DataSource({
|
||||||
type: "postgres",
|
type: "postgres",
|
||||||
host: DB_HOST,
|
host: DB_HOST,
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { AuthController } from "../controllers/AuthController.js";
|
import { AuthHandler } from "../handlers/AuthHandler.js";
|
||||||
import { UserRepository } from "../repositories/UserRepository.js";
|
import { UserRepository } from "../repositories/UserRepository.js";
|
||||||
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
|
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
|
||||||
import {
|
import {
|
||||||
|
|
@ -14,8 +14,13 @@ export const authBasicRoute = "/auth"
|
||||||
const router = Router();
|
const router = Router();
|
||||||
const userRepository = new UserRepository();
|
const userRepository = new UserRepository();
|
||||||
const mapper = new UserDtoEntityMapper();
|
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) => {
|
router.post("/login", async (req, res) => {
|
||||||
console.log("login point called")
|
console.log("login point called")
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { asyncHandler } from "../utils/asyncHandler.js";
|
import { asyncHandler } from "../utils/asyncHandler.js";
|
||||||
import { RecipeRepository } from "../repositories/RecipeRepository.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";
|
import { CompactRecipeDtoEntityMapper } from "../mappers/CompactRecipeDtoEntityMapper.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -12,9 +12,10 @@ const router = Router();
|
||||||
// Inject repo + mapper here
|
// Inject repo + mapper here
|
||||||
const recipeRepository = new RecipeRepository();
|
const recipeRepository = new RecipeRepository();
|
||||||
const compactRecipeMapper = new CompactRecipeDtoEntityMapper();
|
const compactRecipeMapper = new CompactRecipeDtoEntityMapper();
|
||||||
const compactRecipeController = new CompactRecipeController(recipeRepository, compactRecipeMapper);
|
const compactRecipeController = new CompactRecipeHandler(recipeRepository, compactRecipeMapper);
|
||||||
/**
|
/**
|
||||||
* Load header data of all recipes
|
* Load header data of all recipes
|
||||||
|
* Responds with a list of CompactRecipeDtos
|
||||||
*/
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
||||||
import { RecipeDtoEntityMapper } from "../mappers/RecipeDtoEntityMapper.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 { asyncHandler } from "../utils/asyncHandler.js";
|
||||||
import { RecipeDto } from "../dtos/RecipeDto.js";
|
import { RecipeDto } from "../dtos/RecipeDto.js";
|
||||||
import { RecipeIngredientDtoEntityMapper } from "../mappers/RecipeIngredientDtoEntityMapper.js";
|
import { RecipeIngredientDtoEntityMapper } from "../mappers/RecipeIngredientDtoEntityMapper.js";
|
||||||
|
|
@ -20,10 +20,12 @@ const recipeIngredientMapper = new RecipeIngredientDtoEntityMapper();
|
||||||
const recipeIngredientGroupMapper = new RecipeIngredientGroupDtoEntityMapper(recipeIngredientMapper);
|
const recipeIngredientGroupMapper = new RecipeIngredientGroupDtoEntityMapper(recipeIngredientMapper);
|
||||||
const recipeInstructionStepMapper = new RecipeInstructionStepDtoEntityMapper();
|
const recipeInstructionStepMapper = new RecipeInstructionStepDtoEntityMapper();
|
||||||
const recipeMapper = new RecipeDtoEntityMapper(recipeInstructionStepMapper, recipeIngredientGroupMapper);
|
const recipeMapper = new RecipeDtoEntityMapper(recipeInstructionStepMapper, recipeIngredientGroupMapper);
|
||||||
const recipeController = new RecipeController(recipeRepository, recipeMapper);
|
const recipeController = new RecipeHandler(recipeRepository, recipeMapper);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new recipe
|
* Create new recipe
|
||||||
|
* Consumes: RecipeDto
|
||||||
|
* Responds with RecipeDto
|
||||||
*/
|
*/
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
|
|
@ -34,6 +36,10 @@ router.post(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load recipe by id
|
||||||
|
* Responds with RecipeDto
|
||||||
|
*/
|
||||||
router.get(
|
router.get(
|
||||||
"/:id",
|
"/:id",
|
||||||
asyncHandler(async(req, res) => {
|
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(
|
router.put(
|
||||||
"/:id",
|
"/:id",
|
||||||
asyncHandler(async(req, res) =>{
|
asyncHandler(async(req, res) =>{
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import { Router } from "express";
|
import { Router } from "express";
|
||||||
import { UserController } from "../controllers/UserController.js";
|
import { UserHandler } from "../handlers/UserHandler.js";
|
||||||
import { CreateUserRequestDto } from "../dtos/CreateUserRequestDto.js";
|
import { CreateUserRequestDto } from "../dtos/CreateUserRequestDto.js";
|
||||||
import { UserRepository } from "../repositories/UserRepository.js";
|
import { UserRepository } from "../repositories/UserRepository.js";
|
||||||
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
|
import { UserDtoEntityMapper } from "../mappers/UserDtoEntityMapper.js";
|
||||||
|
|
@ -13,10 +13,12 @@ const router = Router();
|
||||||
// Inject repo + mapper here
|
// Inject repo + mapper here
|
||||||
const userRepository = new UserRepository();
|
const userRepository = new UserRepository();
|
||||||
const userMapper = new UserDtoEntityMapper();
|
const userMapper = new UserDtoEntityMapper();
|
||||||
const userController = new UserController(userRepository, userMapper);
|
const userController = new UserHandler(userRepository, userMapper);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new user
|
* Create a new user
|
||||||
|
* Consumes CreateUserRequestDto
|
||||||
|
* Responds with UserDto
|
||||||
*/
|
*/
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
|
|
@ -29,6 +31,7 @@ router.post(
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get user data for current user
|
* Get user data for current user
|
||||||
|
* Responds with UserDto
|
||||||
*/
|
*/
|
||||||
router.get("/me",
|
router.get("/me",
|
||||||
asyncHandler(async (req, res) => {
|
asyncHandler(async (req, res) => {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ import {
|
||||||
UpdateDateColumn,
|
UpdateDateColumn,
|
||||||
} from "typeorm";
|
} from "typeorm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract entity containing basic fields that all entities have in common
|
||||||
|
*/
|
||||||
export abstract class AbstractEntity {
|
export abstract class AbstractEntity {
|
||||||
@PrimaryGeneratedColumn("uuid")
|
@PrimaryGeneratedColumn("uuid")
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import { Entity, Column } from "typeorm";
|
import { Entity, Column } from "typeorm";
|
||||||
import { AbstractEntity } from "./AbstractEntity.js";
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
|
||||||
// @todo Add migration to update table
|
/**
|
||||||
|
* Entity describing a user
|
||||||
|
*/
|
||||||
@Entity({ name: "user" })
|
@Entity({ name: "user" })
|
||||||
export class UserEntity extends AbstractEntity {
|
export class UserEntity extends AbstractEntity {
|
||||||
@Column({ nullable: false, name: "user_name" })
|
@Column({ nullable: false, name: "user_name" })
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { LoginRequestDto } from "../dtos/LoginRequestDto.js";
|
||||||
* Controller responsible for authentication, e.g., login or issueing a token with extended
|
* Controller responsible for authentication, e.g., login or issueing a token with extended
|
||||||
* lifetime
|
* lifetime
|
||||||
*/
|
*/
|
||||||
export class AuthController {
|
export class AuthHandler {
|
||||||
constructor(
|
constructor(
|
||||||
private userRepository: UserRepository,
|
private userRepository: UserRepository,
|
||||||
private mapper: UserDtoEntityMapper
|
private mapper: UserDtoEntityMapper
|
||||||
|
|
@ -6,7 +6,7 @@ import { RecipeRepository } from "../repositories/RecipeRepository.js";
|
||||||
/**
|
/**
|
||||||
* Responsible for loading recipe header data
|
* Responsible for loading recipe header data
|
||||||
*/
|
*/
|
||||||
export class CompactRecipeController {
|
export class CompactRecipeHandler {
|
||||||
constructor(
|
constructor(
|
||||||
private repository: RecipeRepository,
|
private repository: RecipeRepository,
|
||||||
private mapper: CompactRecipeDtoEntityMapper
|
private mapper: CompactRecipeDtoEntityMapper
|
||||||
|
|
@ -5,13 +5,11 @@ import { NotFoundError, ValidationError } from "../errors/httpErrors.js";
|
||||||
import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js";
|
import { RecipeInstructionStepDto } from "../dtos/RecipeInstructionStepDto.js";
|
||||||
import { RecipeIngredientGroupDto } from "../dtos/RecipeIngredientGroupDto.js";
|
import { RecipeIngredientGroupDto } from "../dtos/RecipeIngredientGroupDto.js";
|
||||||
import { RecipeIngredientDto } from "../dtos/RecipeIngredientDto.js";
|
import { RecipeIngredientDto } from "../dtos/RecipeIngredientDto.js";
|
||||||
import { Entity } from "typeorm";
|
|
||||||
import { RecipeEntity } from "../entities/RecipeEntity.js";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controls all recipe specific actions
|
* Controls all recipe specific actions
|
||||||
*/
|
*/
|
||||||
export class RecipeController {
|
export class RecipeHandler {
|
||||||
constructor(
|
constructor(
|
||||||
private recipeRepository: RecipeRepository,
|
private recipeRepository: RecipeRepository,
|
||||||
private mapper: RecipeDtoEntityMapper
|
private mapper: RecipeDtoEntityMapper
|
||||||
|
|
@ -9,7 +9,7 @@ import { UUID } from "crypto";
|
||||||
/**
|
/**
|
||||||
* Controls all user specific actions
|
* Controls all user specific actions
|
||||||
*/
|
*/
|
||||||
export class UserController {
|
export class UserHandler {
|
||||||
constructor(
|
constructor(
|
||||||
private userRepository: UserRepository,
|
private userRepository: UserRepository,
|
||||||
private mapper: UserDtoEntityMapper
|
private mapper: UserDtoEntityMapper
|
||||||
|
|
@ -25,12 +25,16 @@ export abstract class AbstractDtoEntityMapper<
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Abstract methods to be implemented by subclasses
|
/**
|
||||||
abstract toDto(entity: E): D;
|
* Merge entity list with changes contained in DTO list
|
||||||
abstract toEntity(dto: D): E;
|
* @param dtos List of dtos
|
||||||
abstract mergeDtoIntoEntity(dto: D, entity: E): E;
|
* @param entities List of entities
|
||||||
abstract createNewEntity() : E;
|
* @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[]{
|
mergeDtoListIntoEntityList(dtos: D[], entities: E[]) : E[]{
|
||||||
const updatedEntities: E[] = [];
|
const updatedEntities: E[] = [];
|
||||||
const existingMap = new Map(entities?.map(e => [e.id, e]) ?? []);
|
const existingMap = new Map(entities?.map(e => [e.id, e]) ?? []);
|
||||||
|
|
@ -49,4 +53,29 @@ export abstract class AbstractDtoEntityMapper<
|
||||||
|
|
||||||
return updatedEntities;
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,11 +17,11 @@ export class CompactRecipeDtoEntityMapper extends AbstractDtoEntityMapper<Recipe
|
||||||
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
|
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!");
|
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!");
|
throw new Error("Mapping CompactRecipeDto to RecipeEntity is not allowed!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@ import { Repository, DeepPartial } from "typeorm";
|
||||||
import { AppDataSource } from "../data-source.js";
|
import { AppDataSource } from "../data-source.js";
|
||||||
import { AbstractEntity } from "../entities/AbstractEntity.js";
|
import { AbstractEntity } from "../entities/AbstractEntity.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Basic methods for saving, loading and deleting data
|
||||||
|
*/
|
||||||
export abstract class AbstractRepository<T extends AbstractEntity> {
|
export abstract class AbstractRepository<T extends AbstractEntity> {
|
||||||
protected repo: Repository<T>;
|
protected repo: Repository<T>;
|
||||||
|
|
||||||
|
|
@ -22,15 +25,6 @@ export abstract class AbstractRepository<T extends AbstractEntity> {
|
||||||
return this.repo.save(entity);
|
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> {
|
async delete(id: string): Promise<void> {
|
||||||
await this.repo.delete(id as any);
|
await this.repo.delete(id as any);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue