From 027d8c7dee1376e343dcf4d54947e510043e43ce Mon Sep 17 00:00:00 2001 From: Pau Date: Sun, 6 Apr 2025 20:54:16 +0200 Subject: [PATCH] added usersHasPlaces mvc to api --- .../usersHasPlacesController.js | 230 ++++++++++++++++++ .../resource_types/usersHasPlacesModel.js | 60 +++++ .../usersHasPlacesRepository.js | 100 ++++++++ 3 files changed, 390 insertions(+) create mode 100644 src/controllers/resource_types/usersHasPlacesController.js create mode 100644 src/models/resource_types/usersHasPlacesModel.js create mode 100644 src/repositories/resource_types/usersHasPlacesRepository.js diff --git a/src/controllers/resource_types/usersHasPlacesController.js b/src/controllers/resource_types/usersHasPlacesController.js new file mode 100644 index 0000000..7c30b26 --- /dev/null +++ b/src/controllers/resource_types/usersHasPlacesController.js @@ -0,0 +1,230 @@ +import { + getUserHasPlacesListModel, + countUserHasPlacesListModel, + insertUserHasPlacesModel, + modifyUserHasPlacesModel, + softDeleteUserHasPlacesModel +} from "../../models/resource_types/usersHasPlacesModel"; +import { error404 } from "../../utils/errors.js" +import { sendResponseNotFound } from "../../utils/responses.js" +import { noResults } from "../../validators/result-validators.js" +import mysql from "../../adapters/mysql.js" +import { errorHandler } from "../../utils/errors.js" + +const getUserHasPlacesListController = (req, res, next, config) => { + const conn = mysql.start(config) + + Promise.all([ + getUserHasPlacesListModel({...req.query, conn}), + countUserHasPlacesListModel({...req.query, conn}) + ]) + .then(([getResults, countResults]) => { + next({ + _data: {usersHasPlaces: getResults}, + _page: { + totalElements: countResults, + limit: req.query.limit || 100, + page: req.query.page || (countResults && 1) || 0 + } + }) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const getUserHasPlacesByUuidController = (req, res, next, config) => { + const uuid_user_has_places = req.params.uuid + const conn = mysql.start(config) + + getUserHasPlacesListModel({ uuid_user_has_places, conn }) + .then((response) => { + if (noResults(response)) { + const err = error404() + const error = errorHandler(err, config.environment) + return sendResponseNotFound(res, error) + } + + const result = { + _data: { + usersHasPlaces: response + } + } + next(result) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const getUserHasPlacesByUserUuidController = (req, res, next, config) => { + const uuid_user = req.params.uuid + const conn = mysql.start(config) + + getUserHasPlacesListModel({ uuid_user, conn }) + .then((response) => { + if (noResults(response)) { + const err = error404() + const error = errorHandler(err, config.environment) + return sendResponseNotFound(res, error) + } + + const result = { + _data: { + usersHasPlaces: response + } + } + next(result) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const getUserHasPlacesByPlaceUuidController = (req, res, next, config) => { + const uuid_place = req.params.uuid + const conn = mysql.start(config) + + getUserHasPlacesListModel({ uuid_place, conn }) + .then((response) => { + if (noResults(response)) { + const err = error404() + const error = errorHandler(err, config.environment) + return sendResponseNotFound(res, error) + } + + const result = { + _data: { + usersHasPlaces: response + } + } + next(result) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const postUserHasPlacesController = (req, res, next, config) => { + const conn = mysql.start(config) + + insertUserHasPlacesModel({...req.body, conn}) + .then((response) => { + const result = { + _data: { + usersHasPlaces: response + } + } + next(result) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const putUserHasPlacesController = (req, res, next, config) => { + const conn = mysql.start(config) + + modifyUserHasPlacesModel({...req.body, conn}) + .then((response) => { + const result = { + _data: { + usersHasPlaces: response + } + } + next(result) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const deleteUserHasPlacesController = (req, res, next, config) => { + const conn = mysql.start(config) + const uuid_user_has_places = req.params.uuid + const deleted_by = req.auth.user || null + + softDeleteUserHasPlacesModel({uuid_user_has_places, deleted_by, conn}) + .then(() => { + next({}) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const deleteUserHasPlacesByUserUuidController = (req, res, next, config) => { + const conn = mysql.start(config) + const uuid_user = req.params.uuid + const deleted_by = req.auth.user || null + + softDeleteUserHasPlacesModel({uuid_user, deleted_by, conn}) + .then(() => { + next({}) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +const deleteUserHasPlacesByPlaceUuidController = (req, res, next, config) => { + const conn = mysql.start(config) + const uuid_place = req.params.uuid + const deleted_by = req.auth.user || null + + softDeleteUserHasPlacesModel({uuid_place, deleted_by, conn}) + .then(() => { + next({}) + }) + .catch((err) => { + const error = errorHandler(err, config.environment) + return res.status(error.code).json(error) + }) + .finally(() => { + mysql.end(conn) + }) +} + +export { + getUserHasPlacesListController, + getUserHasPlacesByUuidController, + getUserHasPlacesByUserUuidController, + getUserHasPlacesByPlaceUuidController, + postUserHasPlacesController, + putUserHasPlacesController, + deleteUserHasPlacesController, + deleteUserHasPlacesByUserUuidController, + deleteUserHasPlacesByPlaceUuidController +} \ No newline at end of file diff --git a/src/models/resource_types/usersHasPlacesModel.js b/src/models/resource_types/usersHasPlacesModel.js new file mode 100644 index 0000000..5ef4b96 --- /dev/null +++ b/src/models/resource_types/usersHasPlacesModel.js @@ -0,0 +1,60 @@ +import { getUserHasPlacesListQuery, countUserHasPlacesListQuery, insertUserHasPlacesQuery, modifyUserHasPlacesQuery, softDeleteUserHasPlacesQuery +} from "../../repositories/resource_types/usersHasPlacesRepository"; +import { randomUUID as uuidv4 } from 'node:crypto' +import dayjs from 'dayjs' +import mysql from '../../adapters/mysql.js' +import { error404 } from '../../utils/errors.js' + +const getUserHasPlacesListModel = ({conn, ...rest}) => { + const now = dayjs.utc().format('YYYY-MM-DD HH:mm:ss') + const paramsToSearch = {...rest, now} + return mysql + .execute(getUserHasPlacesListQuery(paramsToSearch), conn, paramsToSearch) + .then(queryResult => queryResult.map(({id, created, deleted, createdBy, deletedBy, ...resultFiltered}) => resultFiltered)) +} + +const countUserHasPlacesListModel = ({conn, ...rest}) => { + const now = dayjs.utc().format('YYYY-MM-DD HH:mm:ss') + const paramsToSearch = {...rest, now} + return mysql + .execute(countUserHasPlacesListQuery(paramsToSearch), conn, paramsToSearch) + .then(results => results[0].count) +} + +const insertUserHasPlacesModel = ({conn, ...params}) => { + const now = dayjs.utc().format('YYYY-MM-DD HH:mm:ss') + const uuid = uuidv4() + return mysql + .execute(insertUserHasPlacesQuery({...params, uuid, now}), conn, {...params, uuid, now}) + .then(queryResult => queryResult[1].map(({id, created, deleted, createdBy, deletedBy, ...resultFiltered}) => resultFiltered)) +} + +const modifyUserHasPlacesModel = ({conn, ...params}) => { + return mysql + .execute(modifyUserHasPlacesQuery(params), conn, params) + .then(queryResult => { + const deletedItem = queryResult[1].find(item => item.deleted !== null); + + if (deletedItem) { + throw error404() + } + return queryResult[1].map(({id, created, deleted, createdBy, deletedBy, ...resultFiltered}) => resultFiltered) + }) +} + +const softDeleteUserHasPlacesModel = ({uuid, deleted, deletedBy, conn}) => { + const deletedData = deleted ? dayjs.utc(deleted).format('YYYY-MM-DD HH:mm:ss') : dayjs.utc().format('YYYY-MM-DD HH:mm:ss') + const params = {uuid, deletedBy, deleted: deletedData} + return mysql + .execute(softDeleteUserHasPlacesQuery(params), conn, params) +} + +export { + getUserHasPlacesListModel, + countUserHasPlacesListModel, + insertUserHasPlacesModel, + modifyUserHasPlacesModel, + softDeleteUserHasPlacesModel +} + + diff --git a/src/repositories/resource_types/usersHasPlacesRepository.js b/src/repositories/resource_types/usersHasPlacesRepository.js new file mode 100644 index 0000000..299ca61 --- /dev/null +++ b/src/repositories/resource_types/usersHasPlacesRepository.js @@ -0,0 +1,100 @@ +import { pagination } from "../../utils/pagination"; + +const _userHasPlacesSelectQuery = (_pagination = '') => ({ count }) => ({ uuid, uuidUser, uuidPlace }) => { + const uuidCondition = uuid ? 'AND up.uuid = :uuid ' : ''; + const uuidUserCondition = uuidUser ? 'AND up.fk_user = (SELECT id FROM mydb.users WHERE uuid = :uuidUser)' : ''; + const uuidPlaceCondition = uuidPlace ? 'AND up.fk_place = (SELECT id FROM mydb.places WHERE uuid = :uuidPlace)' : ''; + + return ` + SELECT + up.uuid, + up.fk_user, + up.fk_place, + up.created, + up.createdby, + u.username AS user_username, + u.uuid AS user_uuid, + p.name AS place_name, + p.uuid AS place_uuid + FROM mydb.users_has_places AS up + JOIN mydb.users AS u ON up.fk_user = u.id + JOIN mydb.places AS p ON up.fk_place = p.id + WHERE up.created <= :now + AND (up.deleted > :now OR up.deleted IS NULL) + AND u.deleted IS NULL + AND up.created <= :now + AND (up.deleted > :now OR up.deleted IS NULL) + AND true + ${uuidCondition} + ${uuidUserCondition} + ${uuidPlaceCondition} + ${_pagination} + `; +} + +const getUserHasPlacesListQuery = ({ limit, page, ...rest }) => + _userHasPlacesSelectQuery(pagination({ limit, page }))({ count: false })(rest); + +const countUserHasPlacesListQuery = rest => + _userHasPlacesSelectQuery()({ count: 'COUNT(DISTINCT(up.uuid)) AS count' })(rest); + +const insertUserHasPlacesQuery = ({ uuidUser, uuidPlace, createdBy }) => { + const uuidUserCondition = uuidUser ? '(SELECT id FROM mydb.users WHERE uuid = :uuidUser),' : null; + const uuidPlaceCondition = uuidPlace ? '(SELECT id FROM mydb.places WHERE uuid = :uuidPlace),' : null; + const createdByCondition = createdBy ? 'createdBy = :createdBy' : null; + return ` + INSERT INTO mydb.users_has_places ( + uuid, + fk_user, + fk_place, + created, + createdBy + ) + VALUES ( + :uuid + ${uuidUserCondition} + ${uuidPlaceCondition} + :now, + ${createdByCondition} + ); + SELECT * FROM mydb.users_has_places WHERE uuid = UUID(); + ` +} + +const modifyUserHasPlacesQuery = () => { + const uuidUserCondition = uuidUser ? 'fk_user = (SELECT id FROM mydb.users WHERE uuid = :uuidUser)' : ``; + const uuidPlaceCondition = uuidPlace ? 'fk_place = (SELECT id FROM mydb.places WHERE uuid = :uuidPlace)' : ``; + return ` + UPDATE mydb.users_has_places + SET + ${uuidUserCondition} + ${uuidPlaceCondition} + uuid = :uuid + WHERE + users_has_places.uuid = :uuid + AND + users_has_places.deleted IS NULL; + SELECT * FROM mydb.users_has_places WHERE uuid = :uuid; + ` +} + +const softDeleteUserHasPlacesQuery = () => { + return ` + UPDATE + mydb.users_has_places + SET + deleted = :now, deletedBy = :deletedBy + WHERE + users_has_places.uuid = :uuid + AND + users_has_places.deleted IS NULL; + ` +} + +export { + getUserHasPlacesListQuery, + countUserHasPlacesListQuery, + insertUserHasPlacesQuery, + modifyUserHasPlacesQuery, + softDeleteUserHasPlacesQuery +}; \ No newline at end of file