Магазин на JavaScript, часть 5 из 19. Создание моделей, фильтрация по категрии и бренду
21.11.2021
Теги: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • БазаДанных • ИнтернетМагазин • КаталогТоваров • Корзина • Фреймворк
Создание моделей
Сейчас получилось так, что контроллер выполняет работу модели шаблоне MVC (Model-View-Controller), а моделей у нас и вовсе нет. Давайте исправим это упущение и создадим в директории models
файлы моделей Product.js
, Category.js
, Brand.js
и User.js
. Модели реализуют бизнес-логику приложения и взаимодействуют с базой данных через ORM-библиотеку Sequelize.
import { Product as ProductMapping } from './mapping.js' import AppError from '../errors/AppError.js' class Product { async getAll() { const products = await ProductMapping.findAll() return products } async getOne(id) { const product = await ProductMapping.findByPk(id) if (!product) { throw new Error('Товар не найден в БД') } return product } async create(data, img) { // поскольку image не допускает null, задаем пустую строку const image = FileService.save(img) ?? '' const {name, price, categoryId = null, brandId = null} = data const product = await ProductMapping.create({name, price, image, categoryId, brandId}) return product } async update(id, data, img) { const product = await ProductMapping.findByPk(id) if (!product) { throw new Error('Товар не найден в БД') } // пробуем сохранить изображение, если оно было загружено const file = FileService.save(img) // если загружено новое изображение — надо удалить старое if (file && product.image) { FileService.delete(product.image) } // подготавливаем данные, которые надо обновить в базе данных const { name = product.name, price = product.price, categoryId = product.categoryId, brandId = product.brandId, image = file ? file : product.image } = data await product.update({name, price, image, categoryId, brandId}) return product } async delete(id) { const product = await ProductMapping.findByPk(id) if (!product) { throw new Error('Товар не найден в БД') } await product.destroy() return product } } export default new Product()
import { Category as CategoryMapping } from './mapping.js' import AppError from '../errors/AppError.js' class Category { async getAll() { const categories = await CategoryMapping.findAll() return categories } async getOne(id) { const category = await CategoryMapping.findByPk(id) if (!category) { throw new Error('Категория не найдена в БД') } return category } async create(data) { const {name} = data const category = await CategoryMapping.create({name}) return category } async update(id, data) { const category = await CategoryMapping.findByPk(id) if (!category) { throw new Error('Категория не найдена в БД') } const {name = category.name} = data await category.update({name}) return category } async delete(id) { const category = await CategoryMapping.findByPk(id) if (!category) { throw new Error('Категория не найдена в БД') } await category.destroy() return category } } export default new Category()
import { Brand as BrandMapping } from './mapping.js' import AppError from '../errors/AppError.js' class Brand { async getAll() { const brands = await BrandMapping.findAll() return brands } async getOne(id) { const brand = await BrandMapping.findByPk(id) if (!brand) { throw new Error('Бренд не найден в БД') } return brand } async create(data) { const {name} = data const brand = await BrandMapping.create({name}) return brand } async update(id, data) { const brand = await BrandMapping.findByPk(id) if (!brand) { throw new Error('Бренд не найден в БД') } const {name = brand.name} = data await brand.update({name}) return brand } async delete(id) { const brand = await BrandMapping.findByPk(id) if (!brand) { throw new Error('Бренд не найден в БД') } await brand.destroy() return brand } } export default new Brand()
import { User as UserMapping } from './mapping.js' import AppError from '../errors/AppError.js' class User { async getAll() { const users = await UserMapping.findAll() return users } async getOne(id) { const user = await UserMapping.findByPk(id) if (!user) { throw new Error('Пользователь не найден в БД') } return user } async create(data) { const {email, password, role} = data const user = await UserMapping.create({email, password, role}) return user } async update(id, data) { const user = await UserMapping.findByPk(id) if (!user) { throw new Error('Пользователь не найден в БД') } const { email = user.email, password = user.password, role = user.role } = data await user.update({email, password, role}) return user } async delete(id) { const user = await UserMapping.findByPk(id) if (!user) { throw new Error('Пользователь не найден в БД') } await user.destroy() return user } } export default new User()
Поскольку у нас теперь есть классы моделей, нужно передалать все контроллеры на работу с моделями.
import ProductModel from '../models/Product.js' import AppError from '../errors/AppError.js' class Product { async getAll(req, res, next) { try { const products = await ProductModel.getAll() res.json(products) } catch(e) { next(AppError.badRequest(e.message)) } } async getOne(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id товара') } const product = await ProductModel.getOne(req.params.id) res.json(product) } catch(e) { next(AppError.badRequest(e.message)) } } async create(req, res, next) { try { const product = await ProductModel.create(req.body, req.files?.image) res.json(product) } catch(e) { next(AppError.badRequest(e.message)) } } async update(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id товара') } const product = await ProductModel.update(req.params.id, req.body, req.files?.image) res.json(product) } catch(e) { next(AppError.badRequest(e.message)) } } async delete(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id товара') } const product = await ProductModel.delete(req.params.id) res.json(product) } catch(e) { next(AppError.badRequest(e.message)) } } } export default new Product()
import CategoryModel from '../models/Category.js' import AppError from '../errors/AppError.js' class Category { async getAll(req, res, next) { try { const categories = await CategoryModel.getAll() res.json(categories) } catch(e) { next(AppError.badRequest(e.message)) } } async getOne(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id категории') } const category = await CategoryModel.getOne(req.params.id) res.json(category) } catch(e) { next(AppError.badRequest(e.message)) } } async create(req, res, next) { try { const category = await CategoryModel.create(req.body) res.json(category) } catch(e) { next(AppError.badRequest(e.message)) } } async update(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id категории') } const category = await CategoryModel.update(req.params.id, req.body) res.json(category) } catch(e) { next(AppError.badRequest(e.message)) } } async delete(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id категории') } const category = await CategoryModel.delete(req.params.id) res.json(category) } catch(e) { next(AppError.badRequest(e.message)) } } } export default new Category()
import BrandModel from '../models/Brand.js' import AppError from '../errors/AppError.js' class Brand { async getAll(req, res, next) { try { const brands = await BrandModel.getAll() res.json(brands) } catch(e) { next(AppError.badRequest(e.message)) } } async getOne(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id бренда') } const brand = await BrandModel.getOne(req.params.id) res.json(brand) } catch(e) { next(AppError.badRequest(e.message)) } } async create(req, res, next) { try { const brand = await BrandModel.create(req.body) res.json(brand) } catch(e) { next(AppError.badRequest(e.message)) } } async update(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id бренда') } const brand = await BrandModel.update(req.params.id, req.body) res.json(brand) } catch(e) { next(AppError.badRequest(e.message)) } } async delete(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id бренда') } const brand = await BrandModel.delete(req.params.id) res.json(brand) } catch(e) { next(AppError.badRequest(e.message)) } } } export default new Brand()
import UserModel from '../models/User.js' import AppError from '../errors/AppError.js' class User { async signup(req, res, next) { res.status(200).send('Регистрация пользователя') } async login(req, res, next) { res.status(200).send('Вход в личный кабинет') } async check(req, res, next) { res.status(200).send('Проверка авторизации') } async getAll(req, res, next) { try { const users = await UserModel.getAll() res.json(users) } catch(e) { next(AppError.badRequest(e.message)) } } async getOne(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id пользователя') } const user = await UserModel.getOne(req.params.id) res.json(user) } catch(e) { next(AppError.badRequest(e.message)) } } async create(req, res, next) { try { const user = await UserModel.create(req.body) res.json(brand) } catch(e) { next(AppError.badRequest(e.message)) } } async update(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id пользователя') } const user = await UserModel.update(req.params.id, req.body) res.json(user) } catch(e) { next(AppError.badRequest(e.message)) } } async delete(req, res, next) { try { if (!req.params.id) { throw new Error('Не указан id пользователя') } const user = await UserModel.delete(req.params.id) res.json(user) } catch(e) { next(AppError.badRequest(e.message)) } } } export default new User()
Фильтрация товаров
Нам нужно получать не просто список всех товаров, но и список товаров категории, список товаров бренда и список товаров выбранной категории и выбранного бренда.
import express from 'express' import ProductController from '../controllers/Product.js' const router = new express.Router() // список товаров выбранной категории и выбранного бренда router.get('/getall/categoryId/:categoryId([0-9]+)/brandId/:brandId([0-9]+)', ProductController.getAll) // список товаров выбранной категории router.get('/getall/categoryId/:categoryId([0-9]+)', ProductController.getAll) // список товаров выбранного бренда router.get('/getall/brandId/:brandId([0-9]+)', ProductController.getAll) // список всех товаров каталога router.get('/getall', ProductController.getAll) router.get('/getone/:id([0-9]+)', ProductController.getOne) router.post('/create', ProductController.create) router.put('/update/:id([0-9]+)', ProductController.update) router.delete('/delete/:id([0-9]+)', ProductController.delete) export default router
Внесем изменения в контроллер и модель товара:
import ProductModel from '../models/Product.js' import AppError from '../errors/AppError.js' class Product { async getAll(req, res, next) { try { const products = await ProductModel.getAll(req.params) res.json(products) } catch(e) { next(AppError.badRequest(e.message)) } } /* .......... */ } export default new Product()
import { Product as ProductMapping } from './mapping.js' import FileService from '../services/File.js' import AppError from '../errors/AppError.js' class Product { async getAll(params) { const {categoryId, brandId} = params const where = {} if (categoryId) where.categoryId = categoryId if (brandId) where.brandId = brandId const products = await ProductMapping.findAll({where}) } /* .......... */ } export default new Product()
- Магазин на JavaScript, часть 19 из 19. Редактирование характеристик и рефакторинг приложения
- Магазин на JavaScript, часть 18 из 19. Панель управления: редактирование категорий и брендов
- Магазин на JavaScript, часть 17 из 19. Панель управления: список заказов, категорий и брендов
- Магазин на JavaScript, часть 15 из 19. Работа с заказами на сервере, оформление заказа
- Магазин на JavaScript, часть 14 из 19. Кнопка «Назад», страница товара, корзина покупателя
- Магазин на JavaScript, часть 13 из 19. Хранилище каталога, компонент витрины, кнопка «Назад»
- Магазин на JavaScript, часть12 из 19. Запросы на сервер, состояние приложения, Signup и Login
Поиск: Backend • Express.js • Frontend • JavaScript • Node.js • ORM • React.js • Web-разработка • База данных • Интернет магазин • Каталог товаров • Корзина • Фреймворк