Commit 3468fa69 authored by Pavel Mishakov's avatar Pavel Mishakov

add sequlize, lesson 84 done

parent 54dd76c8
/node_modules
\ No newline at end of file
/node_modules
.env
\ No newline at end of file
[{"title":"Apple","price":77,"description":"This is an apple","id":"ea4f2bd1-2d5a-42ea-99e6-50a125bfe82d"}]
\ No newline at end of file
[{"title":"Apple","price":77,"description":"This is an apple","id":"ea4f2bd1-2d5a-42ea-99e6-50a125bfe82d"},{"title":"Orange","price":999,"description":"This is an orange","id":"ab1e3e0d-7cd1-48ac-a216-4b231e5cd7df"}]
\ No newline at end of file
This diff is collapsed.
......@@ -10,12 +10,21 @@
"author": "",
"license": "ISC",
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"pg": "^8.9.0",
"pg-hstore": "^2.3.4",
"sequelize": "^6.29.0",
"sequelize-typescript": "^2.1.5",
"uuidv4": "^6.2.13"
},
"devDependencies": {
"@types/cors": "^2.8.13",
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.17",
"@types/uuidv4": "^5.0.0",
"@types/validator": "^13.7.12",
"ts-node-dev": "^2.0.0"
}
}
import express, { Router, Request, Response } from 'express'
import { EStatuses } from '../enums/EStatuses'
import IResponse from '../interfaces/IResponse'
const router: Router = express.Router()
router.get('/', (req: Request, res: Response) => {
try {
const response: IResponse = {
status: EStatuses.OK,
result: undefined,
message: 'Server is ok'
}
res.send(response)
} catch (err: unknown) {
const error = err as Error
const response: IResponse = {
status: EStatuses.NOT_OK,
result: undefined,
message: error.message
}
res.status(200).send(response)
export class HealthCheckController {
private router: Router
constructor() {
this.router = express.Router()
this.router.get('/', this.checkHealth)
}
})
export const healthCheckRouter = router
\ No newline at end of file
public getRouter = (): Router => {
return this.router
}
private checkHealth = (req: Request, res: Response): void => {
res.send('Server is OK')
}
}
\ No newline at end of file
import express, { Router, Request, Response } from 'express'
import { productService } from '../services/products'
import { ProductService, productService } from '../services/products'
import { ProductServicePg, productServicePg } from '../services/productsPg'
export class ProductsController {
private router: Router
private service: ProductService | ProductServicePg
const router: Router = express.Router()
constructor() {
this.router = express.Router()
this.router.get('/', this.getProducts)
this.router.get('/:id', this.getProductById)
this.router.post('/', this.addProduct)
switch(process.env.DB) {
case 'file':
this.service = productService
break
case 'postgres':
this.service = productServicePg
break
default:
this.service = productServicePg
}
}
router.get('/', (req: Request, res: Response) => {
const response = productService.getProducts()
res.send(response)
})
public getRouter = (): Router => {
return this.router
}
router.get('/:id', (req: Request, res: Response) => {
const response = productService.getProductById(req.params.id)
res.send(response)
})
private getProducts = async (req: Request, res: Response): Promise<void> => {
const response = await this.service.getProducts()
res.send(response)
}
router.post('/', (req: Request, res: Response) => {
const response = productService.addProduct(req.body)
res.send(response)
})
private getProductById = async (req: Request, res: Response): Promise<void> => {
const response = await this.service.getProductById(req.params.id)
res.send(response)
}
export const productsRouter = router
\ No newline at end of file
private addProduct = async (req: Request, res: Response): Promise<void> => {
const response = await this.service.addProduct(req.body)
res.send(response)
}
}
\ No newline at end of file
import express, { Express } from 'express'
import { config } from './index.config'
import { healthCheckRouter } from './controllers/healthCheck'
import { productsRouter } from './controllers/products'
import { HealthCheckController } from './controllers/healthCheck'
import { ProductsController } from './controllers/products'
import { db } from './repository/fileDB'
import cors from 'cors'
import dotenv from 'dotenv'
import { postgresDB } from './repository/postgresDB'
dotenv.config()
const app: Express = express()
app.use(express.json())
const run = async () => {
db.init()
app.use('/health-check', healthCheckRouter)
app.use('/products', productsRouter)
app.listen(config.port, () => {
console.log(`Server is running on port ${config.port}`)
})
class App {
private app: Express
constructor() {
this.app = express()
this.app.use(express.json())
this.app.use(cors())
}
public init = async (): Promise<void> => {
try {
this.app.use('/health-check', new HealthCheckController().getRouter())
this.app.use('/products', new ProductsController().getRouter())
this.app.listen(process.env.APP_PORT, () => {
console.log(`Server is running on port ${process.env.APP_PORT}`)
})
switch(process.env.DB) {
case 'file':
db.init()
break
case 'postgres':
await postgresDB.init()
break
default:
await postgresDB.init()
}
} catch(err) {
console.log(err)
}
}
}
run()
.then(() => {
console.log('Everything is ok')
})
.catch((err: unknown) => {
const error = err as Error
console.log(error.message)
})
\ No newline at end of file
const app = new App()
app.init()
\ No newline at end of file
export default interface IAction {
id: string
product_id: string
supplier_id: string
action_date: Date
price: number
qty: number
}
\ No newline at end of file
export default interface IActionDto {
product_id: string
supplier_id: string
action_date: Date
price: number
qty: number
}
\ No newline at end of file
export default interface IBrand {
id: string
brand: string
}
\ No newline at end of file
export default interface IBrandDto {
brand: string
}
\ No newline at end of file
export default interface ICategory {
id: string
category: string
description: string
}
\ No newline at end of file
export default interface ICategoryDto {
category: string
description: string
}
\ No newline at end of file
import ISupplier from "./ISupplier"
export default interface IProduct {
id: string
title: string
product: string
price: number
category_id: string
brand_id: string
description: string
suppliers?: ISupplier[]
}
\ No newline at end of file
export default interface IProductDto {
product: string
price: number
description: string
category_id: string
brand_id: string
}
\ No newline at end of file
export default interface IRequest {
title: string
price: number
description: string
}
\ No newline at end of file
......@@ -2,7 +2,7 @@ import { EStatuses } from "../enums/EStatuses";
import IProduct from "./IProduct";
export default interface IResponse {
result: IProduct[] | IProduct | undefined
result: IProduct[] | IProduct | undefined | null
message: string
status: EStatuses
}
\ No newline at end of file
import IProduct from "./IProduct"
export default interface ISupplier {
id: string
supplier: string
address: string
contacts: string
products: IProduct[]
}
\ No newline at end of file
export default interface ISupplierDto {
supplier: string
address: string
contacts: string
}
\ No newline at end of file
import {Model, Table, Column, PrimaryKey, DataType, NotNull, ForeignKey} from 'sequelize-typescript'
import { uuid } from 'uuidv4'
import { Product } from './Product'
import { Supplier } from './Supplier'
@Table({
tableName: 'actions',
timestamps: false
})
export class Action extends Model {
@PrimaryKey
@Column({
type: DataType.STRING,
allowNull: false,
defaultValue: uuid()
})
id!: string
@ForeignKey(() => Product)
@NotNull
@Column({
allowNull: false
})
product_id!: string
@ForeignKey(() => Supplier)
@NotNull
@Column({
allowNull: false
})
supplier_id!: string
@NotNull
@Column({
allowNull: false
})
action_date!: Date
@NotNull
@Column({
allowNull: false
})
price!: number
@NotNull
@Column({
allowNull: false
})
qty!: number
}
\ No newline at end of file
import {Model, Table, Column, PrimaryKey, DataType, NotNull} from 'sequelize-typescript'
import { uuid } from 'uuidv4'
@Table({
tableName: 'brands',
timestamps: false
})
export class Brand extends Model {
@PrimaryKey
@Column({
type: DataType.STRING,
allowNull: false,
defaultValue: uuid()
})
id!: string
@NotNull
@Column({
allowNull: false
})
brand!: string
}
\ No newline at end of file
import {Model, Table, Column, PrimaryKey, DataType, NotNull} from 'sequelize-typescript'
import { uuid } from 'uuidv4'
@Table({
tableName: 'categories',
timestamps: false
})
export class Category extends Model {
@PrimaryKey
@Column({
type: DataType.STRING,
allowNull: false,
defaultValue: uuid()
})
id!: string
@NotNull
@Column({
allowNull: false
})
category!: string
@NotNull
@Column({
allowNull: false
})
description!: string
}
\ No newline at end of file
import {Model, Table, Column, PrimaryKey, DataType, NotNull, ForeignKey, BelongsToMany} from 'sequelize-typescript'
import { uuid } from 'uuidv4'
import { Action } from './Action'
import { Brand } from './Brand'
import { Category } from './Category'
import { Supplier } from './Supplier'
@Table({
tableName: 'products',
timestamps: false
})
export class Product extends Model {
@BelongsToMany(() => Supplier, () => Action)
suppliers!: Supplier[]
@PrimaryKey
@Column({
type: DataType.STRING,
allowNull: false,
defaultValue: uuid()
})
id!: string
@ForeignKey(() => Category)
@Column({
allowNull: true
})
category_id!: string
@ForeignKey(() => Brand)
@Column({
allowNull: true
})
brand_id!: string
@NotNull
@Column({
allowNull: false
})
product!: string
@NotNull
@Column({
allowNull: false
})
description!: string
@NotNull
@Column({
type: DataType.DECIMAL,
allowNull: false
})
price!: number
}
\ No newline at end of file
import {Model, Table, Column, PrimaryKey, DataType, NotNull, BelongsToMany} from 'sequelize-typescript'
import { uuid } from 'uuidv4'
import { Action } from './Action'
import { Product } from './Product'
@Table({
tableName: 'suppliers',
timestamps: false
})
export class Supplier extends Model {
@BelongsToMany(() => Product, () => Action)
products!: Product[]
@PrimaryKey
@Column({
type: DataType.STRING,
allowNull: false,
defaultValue: uuid()
})
id!: string
@NotNull
@Column({
allowNull: false
})
supplier!: string
@NotNull
@Column({
allowNull: false
})
address!: string
@Column({
allowNull: true
})
contacts!: string
}
\ No newline at end of file
import IProduct from "../interfaces/IProduct";
import fs from 'node:fs/promises'
import { uuid } from 'uuidv4';
import IRequest from "../interfaces/IRequest";
import IProductDto from "../interfaces/IProductDto";
class FileDB {
data: IProduct[]
......@@ -34,7 +34,7 @@ class FileDB {
return this.data.find(p => p.id === id);
}
addItem = (item: IRequest): IProduct => {
addItem = (item: IProductDto): IProduct => {
const id: string = uuid()
const product: IProduct = {...item, id}
this.data.push(product);
......
import dotenv from 'dotenv'
import { Sequelize } from 'sequelize-typescript'
dotenv.config()
import path from 'path'
export class PostgresDB {
private sequelize: Sequelize
constructor() {
this.sequelize = new Sequelize({
database: process.env.PG_DB,
dialect: 'postgres',
host: process.env.PG_HOST,
username: process.env.PG_USER,
password: process.env.PG_PASS,
storage: ':memory',
models: [path.join(__dirname, '../models')]
})
}
public getSequelize = (): Sequelize => {
return this.sequelize
}
public close = async(): Promise<void> => {
await this.sequelize.close()
}
public init = async (): Promise<void> => {
try {
await this.sequelize.authenticate()
await this.sequelize.sync({
alter: true
})
console.log('DB postgres is connected')
} catch (err) {
console.log(err)
}
}
}
export const postgresDB = new PostgresDB()
\ No newline at end of file
import { EStatuses } from "../enums/EStatuses"
import IProduct from "../interfaces/IProduct"
import IRequest from "../interfaces/IRequest"
import IProductDto from "../interfaces/IProductDto"
import IResponse from "../interfaces/IResponse"
import { db } from "../repository/fileDB"
class ProductService {
getProducts = (): IResponse => {
export class ProductService {
public getProducts = (): IResponse => {
try {
const data = db.getItems()
const response: IResponse = {
status: EStatuses.OK,
result: data,
message: ''
message: 'Products found'
}
return response
} catch (err: unknown) {
......@@ -25,7 +25,7 @@ class ProductService {
}
}
getProductById = (id: string): IResponse => {
public getProductById = (id: string): IResponse => {
try {
const data: IProduct | undefined = db.getItemById(id)
const response: IResponse = {
......@@ -45,7 +45,7 @@ class ProductService {
}
}
addProduct = (product: IRequest): IResponse => {
public addProduct = (product: IProductDto): IResponse => {
try {
const data: IProduct | undefined = db.addItem(product)
const response: IResponse = {
......
import { EStatuses } from "../enums/EStatuses"
import IProduct from "../interfaces/IProduct"
import IProductDto from "../interfaces/IProductDto"
import IResponse from "../interfaces/IResponse"
import { Product } from "../models/Product"
import { Op } from 'sequelize'
export class ProductServicePg {
public getProducts = async (): Promise<IResponse> => {
try {
const data = await Product.findAll()
// {
// where: {
// title: {
// [Op.like]: '%App%'
// }
// }
// }
const response: IResponse = {
status: EStatuses.OK,
result: data,
message: 'Products found'
}
return response
} catch (err: unknown) {
const error = err as Error
const response: IResponse = {
status: EStatuses.NOT_OK,
result: undefined,
message: error.message
}
return response
}
}
public getProductById = async (id: string): Promise<IResponse> => {
try {
const data: IProduct | null = await Product.findByPk(id)
const response: IResponse = {
status: EStatuses.OK,
result: data,
message: ''
}
return response
} catch (err: unknown) {
const error = err as Error
const response: IResponse = {
status: EStatuses.NOT_OK,
result: undefined,
message: error.message
}
return response
}
}
public addProduct = async (product: IProductDto): Promise<IResponse> => {
try {
const data: IProduct | undefined = await Product.create({...product})
const response: IResponse = {
status: EStatuses.OK,
result: data,
message: ''
}
return response
} catch (err: unknown) {
const error = err as Error
const response: IResponse = {
status: EStatuses.NOT_OK,
result: undefined,
message: error.message
}
return response
}
}
}
export const productServicePg = new ProductServicePg()
\ No newline at end of file
......@@ -14,8 +14,8 @@
"target": "es2020", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
// "jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
"experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
"emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment