mongoose + tests

This commit is contained in:
Primakov Alexandr Alexandrovich
2024-10-16 11:06:23 +03:00
parent 2cfcd7347b
commit 4b0d9b4dbc
1295 changed files with 4579 additions and 1719 deletions

View File

@@ -0,0 +1,198 @@
const ObjectId = require('mongodb').ObjectID
const { getDB } = require('../../../utils/mongo')
const dishData = require('./data/dishdata.json')
const tabsData = require('./data/tabs.json')
const { getResponse, _idToIdArray, _idToId } = require('./utils/common')
const DISH_COLLECTION = 'default_dishes'
const TAB_COLLECTION = 'default_tabs'
const USER_COLLECTION = 'users'
const _idRemove = (data) => {
const { _id, ...rest } = data
return {
_id: undefined,
...rest,
}
}
let db = null
const connect = async () => {
db = await getDB('dish')
}
const init = async () => {
await connect()
const dishesCollection = db.collection(DISH_COLLECTION)
const findDish = await dishesCollection.find({
}).toArray()
if (findDish.length === 0) {
await dishesCollection.insertMany(dishData)
}
const tabsCollection = db.collection(TAB_COLLECTION)
const findTabs = await tabsCollection.find({
}).toArray()
if (findTabs.length === 0) {
await tabsCollection.insertMany(tabsData)
}
const usersCollection = db.collection(USER_COLLECTION)
}
init()
const getDish = async () => {
if (db === null) throw new Error('no db connection')
try {
const dishesCollection = db.collection(DISH_COLLECTION)
const defaultDishes = await dishesCollection.find({}).toArray()
return _idToIdArray(defaultDishes)
} catch (e) {
throw new Error(e)
}
}
const getTabs = async () => {
if (db === null) throw new Error('no db connection')
try {
const tabsCollection = db.collection(TAB_COLLECTION)
const defaultTabs = await tabsCollection.find({}).toArray()
return _idToIdArray(defaultTabs)
} catch (e) {
throw new Error(e)
}
}
const updateTab = async (id, timestampsNew) => {
if (db === null) throw new Error('no db connection')
try {
const tabsCollection = db.collection(TAB_COLLECTION)
const findData = await tabsCollection.findOne({
_id: new ObjectId(id),
})
if (!findData) throw new Error('Tabs is not exist')
const filter = {
_id: new ObjectId(id),
}
const options = {
upsert: false,
}
const updateDoc = {
$set: {
timeStamps: timestampsNew,
},
}
const result = await tabsCollection.updateOne(filter, updateDoc, options)
return _idToId(result)
} catch (e) {
throw new Error(e)
}
}
const getUsers = async () => {
if (db === null) throw new Error('no db connection')
try {
const usersCollection = db.collection(USER_COLLECTION)
const users = await usersCollection.find({
}).project({
_id: 0,
}).toArray()
return _idToIdArray(users)
} catch (e) {
throw new Error(e)
}
}
const getUserByEmail = async ({ email }) => {
if (db === null) throw new Error('no db connection')
try {
const usersCollection = db.collection(USER_COLLECTION)
const user = await usersCollection.findOne(
{
email,
},
{
projection:
{
_id: 0,
},
},
)
return user
} catch (e) {
throw new Error(e)
}
}
const addUser = async ({ email, hash }) => {
if (db === null) throw new Error('no db connection')
try {
const usersCollection = db.collection(USER_COLLECTION)
const user = await usersCollection.findOne(
{
email,
},
)
if (user) throw new Error('User is exist')
const insertData = await usersCollection.insertOne(
{
email,
hash,
},
)
const { insertedCount, ops } = insertData
if (insertedCount) {
return _idRemove(ops[0])
}
throw new Error('insert error')
} catch (e) {
throw new Error(e)
}
}
const getDishById = async ({ id }) => {
if (db === null) throw new Error('no db connection')
try {
const dishesCollection = db.collection(DISH_COLLECTION)
const dish = await dishesCollection.findOne(
{
_id: new ObjectId(id),
},
)
return _idToId(dish)
} catch (e) {
throw new Error(e)
}
}
const getDishByCategory = async ({ cat, id }) => {
if (db === null) throw new Error('no db connection')
try {
const dishesCollection = db.collection(DISH_COLLECTION)
const dish = await dishesCollection.find(
{
_id:
{
$ne: new ObjectId(id),
},
category: cat,
},
).toArray()
return _idToIdArray(dish)
} catch (e) {
throw new Error(e)
}
}
module.exports = {
getDish,
getTabs,
getDishById,
getDishByCategory,
getUsers,
addUser,
getUserByEmail,
updateTab,
}

View File

@@ -0,0 +1,116 @@
[
{
"category": "Salads",
"title": "Qwerty salad",
"image": "qwertysalad.jpg",
"price": 244,
"description": "Fragrant crispy keys dressed with coffee, beer or coca-cola"
},
{
"category": "Salads",
"title": "Fibonacci salad",
"image": "fibonaccisalad.jpg",
"price": 199,
"description": "Refined taste of yesterday salad, complimented by salad from two days ago"
},
{
"category": "Salads",
"title": "RNG salad",
"image": "rngsalad.jpg",
"price": 317,
"description": "Exquisite original taste of fully natural, randomly generated numbers"
},
{
"category": "Salads",
"title": "Merge request",
"image": "mergerequestsalad.jpg",
"price": 241,
"description": "Non-merged salad, ideal for merge conflicts intolerance"
},
{
"category": "CFood",
"title": "SalmON",
"image": "salmon.jpg",
"price": 441,
"description": "Salmon with user-friendly interface"
},
{
"category": "CFood",
"title": "SalmOFF",
"image": "salmoff1.jpg",
"price": 16,
"description": "The pink Salmon skeleton is perfect for research and debugging"
},
{
"category": "CFood",
"title": "Develobster",
"image": "develobster.jpg",
"price": 1024,
"description": "High skilled senior frontend develobster"
},
{
"category": "CFood",
"title": "8-bit Octopus",
"image": "octopus1.jpg",
"price": 500,
"description": "8-bit Octopus summary"
},
{
"category": "Soups",
"title": "Hooks & props",
"image": "hookspropssoup.jpg",
"price": 411,
"description": "A rich fragrant soup with a large set of properties and states that is easy to hook"
},
{
"category": "Soups",
"title": "Float points",
"image": "floatpointsoup.jpg",
"price": 433,
"description": "A light soup, the original taste and unique aroma of which is provided by floating points"
},
{
"category": "Soups",
"title": "BorscHTML",
"image": "borschtml.jpg",
"price": 422,
"description": "Marked up by sour cream soup based on thoroughly tested bit-root"
},
{
"category": "Soups",
"title": "Try-catch",
"image": "trycatch3.jpg",
"price": 455,
"description": "Soup for real gourmets familiar with advanced try-catch technologies"
},
{
"category": "Desserts",
"title": "Fractal",
"image": "fractal3.jpg",
"price": 378,
"description": "Self-similar fractal produced by recursion from dark chocolate and cream"
},
{
"category": "Desserts",
"title": "Debugged apple",
"image": "apple.jpg",
"price": 85,
"description": "Eco-friendly apple debugged and tested in the most thorough way"
},
{
"category": "Desserts",
"title": "Cookies",
"image": "cookies2.jpg",
"price": 111,
"description": "We also use cookies, but not for this"
},
{
"category": "Desserts",
"title": "Syntactic sugar",
"image": "sugar.jpg",
"price": 100,
"description": "Syntactic sugar which make it easier for humans to code. Enjoy it!"
}
]

View File

@@ -0,0 +1,137 @@
[
{
"location": [
[0, 1],
[1, 1],
[1, 0]
],
"timeStamps": ["2022-12-12", "2022-12-13"]
},
{
"location": [
[1, 1, 1],
[0, 1, 0]
],
"timeStamps": []
},
{
"location": [
[1, 1],
[0, 1],
[0, 1]
],
"timeStamps": ["2022-12-13", "2022-12-14"]
},
{
"location": [
[1, 1],
[1, 0],
[1, 0]
],
"timeStamps": ["2022-12-14"]
},
{
"location": [
[1, 1],
[1, 1]
],
"timeStamps": ["2022-12-15", "2022-12-16"]
},
{
"location": [
[1, 0],
[1, 1],
[0, 1]
],
"timeStamps": ["2022-12-15"]
},
{
"location": [
[1, 0],
[1, 1],
[1, 0]
],
"timeStamps": []
},
{
"location": [
[1, 1],
[1, 1]
],
"timeStamps": ["2022-12-12"]
},
{
"location": [
[0, 1],
[1, 1],
[0, 1]
],
"timeStamps": []
},
{
"location": [
[1, 0],
[1, 0],
[1, 1]
],
"timeStamps": []
},
{
"location": [
[1, 0],
[1, 1],
[0, 1]
],
"timeStamps": []
},
{
"location": [
[0, 1],
[0, 1],
[1, 1]
],
"timeStamps": []
},
{
"location": [
[0, 1, 1],
[1, 1, 0]
],
"timeStamps": []
},
{
"location": [
[1, 1, 1],
[0, 1, 0]
],
"timeStamps": []
},
{
"location": [
[1, 1, 1],
[1, 0, 0]
],
"timeStamps": []
},
{
"location": [
[1, 0, 0],
[1, 1, 1]
],
"timeStamps": []
},
{
"location": [
[0, 1, 0],
[1, 1, 1]
],
"timeStamps": ["2022-12-12"]
},
{
"location": [
[0, 0, 1],
[1, 1, 1]
],
"timeStamps": ["2022-12-13"]
}
]

View File

@@ -0,0 +1,8 @@
const router = require('express').Router()
router.use('/auth', require('./routes/auth'))
router.use('/dish', require('./routes/dish'))
router.use('/reservation', require('./routes/reservation'))
router.use('/order', require('./routes/order'))
module.exports = router

View File

@@ -0,0 +1,12 @@
const checkRequiredMidleware = (options) => (req, res, next) => {
// eslint-disable-next-line no-restricted-syntax
for (const option of options) {
if (!req.body[option]) {
res.status(400).send(`Required field ${option} is not present`)
return
}
}
next()
}
module.exports = checkRequiredMidleware

View File

@@ -0,0 +1,47 @@
const authRouter = require('express').Router()
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const { JWT_TOKEN, SALT } = require('./key')
const { getResponse } = require('../utils/common')
const { getUsers, addUser, getUserByEmail } = require('../controller')
const checkRequiredMidleware = require('../midlewares/checkRequired.midleware')
authRouter.get('/users', async (req, res) => {
let error = null
const dishData = await getUsers().catch((e) => error = e.message)
res.send(getResponse(error, dishData))
})
authRouter.post(
'/register',
checkRequiredMidleware(['email', 'password']),
async (req, res) => {
const { email, password } = req.body
const hash = await bcrypt.hash(password, SALT)
let error = null
const user = await addUser({ email, hash }).catch((e) => error = e.message)
res.send(getResponse(error, user))
},
)
authRouter.post(
'/login',
checkRequiredMidleware(['email', 'password']),
async (req, res) => {
const { email, password } = req.body;
let error = null
const user = await getUserByEmail({ email }).catch((e) => error = e.message)
if (user) {
const passwordCorrect = await bcrypt.compare(password, user.hash)
if (passwordCorrect) {
// eslint-disable-next-line no-undef
const token = jwt.sign({ email }, JWT_TOKEN)
res.send({ email, token })
return
}
}
res.status(400).send('Incorrect email or password')
},
)
module.exports = authRouter

View File

@@ -0,0 +1,33 @@
const dishRouter = require('express').Router()
const ObjectId = require('mongodb').ObjectID
const { getResponse } = require('../utils/common')
const { getDish, getTabs, getDishById, getDishByCategory } = require('../controller')
dishRouter.get('/', async (req, res) => {
let error = null
const dishData = await getDish().catch((e) => error = e.message)
res.send(getResponse(error, dishData))
})
dishRouter.get('/reservation', async (req, res) => {
let error = null
const tabData = await getTabs().catch((e) => error = e.message)
res.send(getResponse(error, tabData))
})
dishRouter.get('/alsolike/:dishId', async (req, res) => {
let error = null
const dish = await getDishById({ id: req.params.dishId }).catch((e) => error = e.message)
const categoryArr = await getDishByCategory({
cat: dish.category, id: req.params.dishId,
}).catch((e) => error = e.message)
res.status(200).send(getResponse(error, categoryArr))
})
dishRouter.get('/:dishId', async (req, res) => {
let error = null
const dishData = await getDishById({ id: req.params.dishId }).catch((e) => error = e.message)
res.send(getResponse(error, dishData))
})
module.exports = dishRouter

View File

@@ -0,0 +1,7 @@
const JWT_TOKEN = 'secret'
const SALT = 3
module.exports = {
JWT_TOKEN,
SALT,
}

View File

@@ -0,0 +1,8 @@
const orderRouter = require('express').Router()
orderRouter.post('/', (req, res) => {
const orderNumber = 2003
res.status(200).send({ orderNumber })
})
module.exports = orderRouter

View File

@@ -0,0 +1,32 @@
const reservationRouter = require('express').Router()
const { getTabs, updateTab } = require('../controller')
reservationRouter.get('/', async (req, res) => {
let error = null
const tabData = await getTabs().catch((e) => error = e.message)
if (error) {
res.status(400).send(error)
} else {
res.status(200).send(tabData)
}
})
reservationRouter.post('/post', async (req, res) => {
let error = null
const data = req.body
console.log(data.length)
const promises = []
for (let i = 0; i < data.length; i++) {
const item = data[i]
const result = updateTab(item.id, item.timeStamps)
promises.push(result)
}
await Promise.all(promises).catch((e) => error = e.message)
if (error) {
res.status(400).send(error)
} else {
res.status(200).send()
}
})
module.exports = reservationRouter

View File

@@ -0,0 +1,34 @@
const _idToId = (data) => {
const { _id, ...rest } = data
return {
id: _id,
...rest,
}
}
const _idToIdArray = (data) => {
const _idToIdMap = data.map((item) => _idToId(item))
return _idToIdMap
}
const getResponse = (error, data, success = true) => {
if (error) {
return {
success: false,
error,
}
}
return {
success,
data,
}
}
module.exports = {
getResponse,
_idToIdArray,
_idToId,
}