From 98ad2d5acb43fb701607d4adaddd9b8bc7f0276b Mon Sep 17 00:00:00 2001 From: Vlad Demchuk Date: Wed, 21 Feb 2024 22:11:33 +0200 Subject: [PATCH] Complete task --- package-lock.json | 164 ++++++++++++++++++++++++++ package.json | 3 +- src/controllers/expense.controller.js | 126 ++++++++++++++++++++ src/controllers/user.controller.js | 87 ++++++++++++++ src/createServer.js | 18 ++- src/db.js | 2 +- src/middleware/validateAndParseId.js | 17 +++ src/models/Expense.model.js | 35 +++++- src/models/User.model.js | 13 +- src/routes/expense.route.js | 19 +++ src/routes/user.route.js | 19 +++ src/services/expense.service.js | 86 ++++++++++++++ src/services/user.service.js | 37 ++++++ src/utils/generateUniqueId.js | 7 ++ 14 files changed, 626 insertions(+), 7 deletions(-) create mode 100644 src/controllers/expense.controller.js create mode 100644 src/controllers/user.controller.js create mode 100644 src/middleware/validateAndParseId.js create mode 100644 src/routes/expense.route.js create mode 100644 src/routes/user.route.js create mode 100644 src/services/expense.service.js create mode 100644 src/services/user.service.js create mode 100644 src/utils/generateUniqueId.js diff --git a/package-lock.json b/package-lock.json index 3214033f..035fd36d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1498,6 +1498,12 @@ } } }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, "accepts": { "version": "1.3.8", "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", @@ -1809,6 +1815,12 @@ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==", "dev": true }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, "body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -1965,6 +1977,22 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", "dev": true }, + "chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, "ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", @@ -3156,6 +3184,15 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -3269,6 +3306,12 @@ "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", "dev": true }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "dev": true + }, "import-fresh": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz", @@ -3424,6 +3467,15 @@ "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", "dev": true }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, "is-callable": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", @@ -3451,6 +3503,12 @@ "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, "is-fullwidth-code-point": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", @@ -3463,6 +3521,15 @@ "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", "dev": true }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, "is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5240,6 +5307,53 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "nodemon": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.3.tgz", + "integrity": "sha512-7jH/NXbFPxVaMwmBCC2B9F/V6X1VkEdNgx3iu9jji8WxWcvhMWkmhNWhI5077zknOnZnBzba9hZP6bCPJLSReQ==", + "dev": true, + "requires": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "dependencies": { + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -5661,6 +5775,12 @@ "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "dev": true }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, "pump": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", @@ -5726,6 +5846,15 @@ "read-pkg": "^2.0.0" } }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, "regexpp": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", @@ -5991,6 +6120,26 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "dev": true, + "requires": { + "semver": "^7.5.3" + }, + "dependencies": { + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, "sinon": { "version": "9.2.4", "resolved": "https://registry.npmjs.org/sinon/-/sinon-9.2.4.tgz", @@ -6356,6 +6505,15 @@ "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", "integrity": "sha512-OsLcGGbYF3rMjPUf8oKktyvCiUxSbqMMS39m33MAjLTC1DVIH6x3WSt63/M77ihI09+Sdfk1AXvfhCEeUmC7mg==" }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, "tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -6404,6 +6562,12 @@ "mime-types": "~2.1.24" } }, + "undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "dev": true + }, "universal-user-agent": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-5.0.0.tgz", diff --git a/package.json b/package.json index e535a439..6f1173e7 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "eslint": "^5.16.0", "eslint-plugin-jest": "^22.4.1", "eslint-plugin-node": "^8.0.1", - "jest": "^29.7.0" + "jest": "^29.7.0", + "nodemon": "^3.0.3" }, "mateAcademy": { "projectType": "nodeJs" diff --git a/src/controllers/expense.controller.js b/src/controllers/expense.controller.js new file mode 100644 index 00000000..a9bfd913 --- /dev/null +++ b/src/controllers/expense.controller.js @@ -0,0 +1,126 @@ +'use strict'; + +const expenseService = require('../services/expense.service'); +const userService = require('../services/user.service'); + +const get = async(req, res) => { + const { userId, categories, from, to } = req.query; + + if (userId || categories || from || to) { + const parsedId = parseInt(userId, 10); + + if (userId && isNaN(parsedId)) { + res.sendStatus(400); + + return; + } + + const expensesByQueries = await expenseService.getByQueries(req.query); + + res.send(expensesByQueries); + + return; + } + + const allExpenses = await expenseService.getAll(); + + res.send(allExpenses); +}; + +const getOne = async(req, res) => { + const { parsedId } = req; + + const expense = await expenseService.getById(parsedId); + + if (!expense) { + res.sendStatus(404); + + return; + } + + res.send(expense); +}; + +const create = async(req, res) => { + const { userId, spentAt, title, amount, category, note } = req.body; + + const user = await userService.getById(userId); + const isDateValid = !isNaN(Date.parse(spentAt)); + + if (!user + || !isDateValid + || typeof title !== 'string' + || typeof amount !== 'number') { + res.sendStatus(400); + + return; + } + + const expense = await expenseService.create({ + userId, + spentAt, + title, + amount, + category, + note, + }); + + res.status(201).send(expense); +}; + +const remove = async(req, res) => { + const { parsedId } = req; + + const expense = expenseService.getById(parsedId); + + if (!expense) { + res.sendStatus(404); + + return; + } + + await expenseService.remove(parsedId); + + res.sendStatus(204); +}; + +const update = async(req, res) => { + const { parsedId } = req; + const { title, amount, category, note } = req.body; + + const expense = await expenseService.getById(parsedId); + + if (!expense) { + res.sendStatus(404); + + return; + } + + if ((title && typeof title !== 'string') + || (amount && typeof amount !== 'number') + || (category && typeof category !== 'string') + || (note && typeof note !== 'string')) { + res.sendStatus(400); + + return; + } + + const expenseToUpdate = { + ...expense, + ...req.body, + }; + + await expenseService.update(parsedId, expenseToUpdate); + + const updatedExpense = await expenseService.getById(parsedId); + + res.send(updatedExpense); +}; + +module.exports = { + get, + getOne, + remove, + update, + create, +}; diff --git a/src/controllers/user.controller.js b/src/controllers/user.controller.js new file mode 100644 index 00000000..17627e2e --- /dev/null +++ b/src/controllers/user.controller.js @@ -0,0 +1,87 @@ +'use strict'; + +const userService = require('../services/user.service.js'); + +const get = async(req, res) => { + res.send(await userService.getAll()); +}; + +const getOne = async(req, res) => { + const { parsedId } = req; + + const user = await userService.getById(parsedId); + + if (!user) { + res.sendStatus(404); + + return; + } + + res.send(user); +}; + +const create = async(req, res) => { + const { name } = req.body; + + if (!name || typeof name !== 'string') { + res.sendStatus(400); + + return; + } + + const user = await userService.create(name); + + res.status(201).send(user); +}; + +const remove = async(req, res) => { + const { parsedId } = req; + + const user = await userService.getById(parsedId); + + if (!user) { + res.sendStatus(404); + + return; + } + + await userService.remove(parsedId); + + res.sendStatus(204); +}; + +const update = async(req, res) => { + const { parsedId } = req; + const { name } = req.body; + + const user = userService.getById(parsedId); + + if (!user) { + res.sendStatus(404); + + return; + } + + if (!name || typeof name !== 'string') { + res.sendStatus(400); + + return; + } + + await userService.update({ + parsedId, + name, + }); + + const updatedUser = await userService.getById(parsedId); + + res.send(updatedUser); +}; + +module.exports = { + get, + getOne, + create, + remove, + update, +}; diff --git a/src/createServer.js b/src/createServer.js index 1ea5542d..1ce25eb1 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,20 @@ 'use strict'; -const createServer = () => { - // your code goes here -}; +const express = require('express'); +const { router: userRouter } = require('./routes/user.route'); +const { router: expenseRouter } = require('./routes/expense.route'); + +function createServer() { + const app = express(); + + app.use(express.json()); + + app.use('/users', userRouter); + + app.use('/expenses', expenseRouter); + + return app; +} module.exports = { createServer, diff --git a/src/db.js b/src/db.js index 1ba3046c..737d9ccc 100644 --- a/src/db.js +++ b/src/db.js @@ -26,7 +26,7 @@ const sequelize = new Sequelize({ host: POSTGRES_HOST || 'localhost', dialect: 'postgres', port: POSTGRES_PORT || 5432, - password: POSTGRES_PASSWORD || '123', + password: POSTGRES_PASSWORD || '123123', }); module.exports = { diff --git a/src/middleware/validateAndParseId.js b/src/middleware/validateAndParseId.js new file mode 100644 index 00000000..3a2be324 --- /dev/null +++ b/src/middleware/validateAndParseId.js @@ -0,0 +1,17 @@ +'use strict'; + +const validateAndParseId = (req, res, next) => { + const { id } = req.params; + const parsedId = parseInt(id, 10); + + if (isNaN(parsedId)) { + res.sendStatus(400); + + return; + } + + req.parsedId = parsedId; + next(); +}; + +module.exports = { validateAndParseId }; diff --git a/src/models/Expense.model.js b/src/models/Expense.model.js index 567e1c3e..b0208032 100644 --- a/src/models/Expense.model.js +++ b/src/models/Expense.model.js @@ -1,9 +1,42 @@ 'use strict'; const { sequelize } = require('../db.js'); +const { DataTypes } = require('sequelize'); const Expense = sequelize.define( - // your code goes here + 'Expense', + { + userId: { + type: DataTypes.INTEGER, + allowNull: false, + }, + spentAt: { + type: DataTypes.DATE, + defaultValue: DataTypes.NOW, + allowNull: false, + }, + title: { + type: DataTypes.STRING, + allowNull: false, + }, + amount: { + type: DataTypes.INTEGER, + allowNull: false, + }, + category: { + type: DataTypes.STRING, + allowNull: true, + }, + note: { + type: DataTypes.STRING, + allowNull: true, + }, + }, + { + tableName: 'expenses', + createdAt: false, + updatedAt: false, + } ); module.exports = { diff --git a/src/models/User.model.js b/src/models/User.model.js index 61861c9e..1e9dfc2d 100644 --- a/src/models/User.model.js +++ b/src/models/User.model.js @@ -1,9 +1,20 @@ 'use strict'; const { sequelize } = require('../db.js'); +const { DataTypes } = require('sequelize'); const User = sequelize.define( - // your code goes here + 'User', + { + name: { + type: DataTypes.STRING, + allowNull: false, + }, + }, { + tableName: 'users', + createdAt: false, + updatedAt: false, + }, ); module.exports = { diff --git a/src/routes/expense.route.js b/src/routes/expense.route.js new file mode 100644 index 00000000..ff406ab0 --- /dev/null +++ b/src/routes/expense.route.js @@ -0,0 +1,19 @@ +'use strict'; + +const express = require('express'); +const expenseController = require('../controllers/expense.controller'); +const { validateAndParseId } = require('../middleware/validateAndParseId'); + +const router = express.Router(); + +router.get('/', expenseController.get); + +router.get('/:id', validateAndParseId, expenseController.getOne); + +router.post('/', expenseController.create); + +router.delete('/:id', validateAndParseId, expenseController.remove); + +router.patch('/:id', validateAndParseId, expenseController.update); + +module.exports = { router }; diff --git a/src/routes/user.route.js b/src/routes/user.route.js new file mode 100644 index 00000000..fc2ca635 --- /dev/null +++ b/src/routes/user.route.js @@ -0,0 +1,19 @@ +'use strict'; + +const express = require('express'); +const userController = require('../controllers/user.controller'); +const { validateAndParseId } = require('../middleware/validateAndParseId'); + +const router = express.Router(); + +router.get('/', userController.get); + +router.get('/:id', validateAndParseId, userController.getOne); + +router.post('/', userController.create); + +router.delete('/:id', validateAndParseId, userController.remove); + +router.patch('/:id', validateAndParseId, userController.update); + +module.exports = { router }; diff --git a/src/services/expense.service.js b/src/services/expense.service.js new file mode 100644 index 00000000..63123c12 --- /dev/null +++ b/src/services/expense.service.js @@ -0,0 +1,86 @@ +'use strict'; + +const { models } = require('../models/models'); +const { Op } = require('sequelize'); + +const { Expense } = models; + +const getAll = () => { + return Expense.findAll(); +}; + +const getByQueries = ({ + userId, + categories, + from, + to, +}) => { + const whereClause = {}; + + if (userId) { + whereClause.userId = userId; + } + + if (categories) { + const categoriesArray = categories.split(','); + + whereClause.category = { [Op.in]: categoriesArray }; + } + + if (from) { + whereClause.spentAt = { + ...whereClause.spentAt, + [Op.gte]: from, + }; + } + + if (to) { + whereClause.spentAt = { + ...whereClause.spentAt, + [Op.lte]: to, + }; + } + + return Expense.findAll({ where: whereClause }); +}; + +const getById = (id) => { + return Expense.findByPk(id); +}; + +const create = ({ + userId, + spentAt, + title, + amount, + category, + note, +}) => { + const expense = Expense.create({ + userId, + spentAt, + title, + amount, + category, + note, + }); + + return expense; +}; + +const remove = async(id) => { + await Expense.destroy({ where: { id } }); +}; + +const update = async(id, expense) => { + await Expense.update({ ...expense }, { where: { id } }); +}; + +module.exports = { + getAll, + getByQueries, + getById, + remove, + update, + create, +}; diff --git a/src/services/user.service.js b/src/services/user.service.js new file mode 100644 index 00000000..92fed01c --- /dev/null +++ b/src/services/user.service.js @@ -0,0 +1,37 @@ +'use strict'; + +const { models } = require('../models/models'); + +const { User } = models; + +const getAll = () => { + return User.findAll(); +}; + +const getById = (id) => { + return User.findByPk(id); +}; + +const create = (name) => { + return User.create({ name }); +}; + +const remove = async(id) => { + await User.destroy({ + where: { + id, + }, + }); +}; + +const update = async({ parsedId, name }) => { + await User.update({ name }, { where: { id: parsedId } }); +}; + +module.exports = { + getAll, + getById, + create, + remove, + update, +}; diff --git a/src/utils/generateUniqueId.js b/src/utils/generateUniqueId.js new file mode 100644 index 00000000..fc913026 --- /dev/null +++ b/src/utils/generateUniqueId.js @@ -0,0 +1,7 @@ +'use strict'; + +const generateUniqueId = () => { + return Math.floor(Math.random() * Date.now()); +}; + +module.exports = { generateUniqueId };