# Реалізація інформаційного та програмного забезпечення

# SQL-скрипт

-- MySQL Script generated by MySQL Workbench
-- Wed Apr 26 17:39:47 2023
-- Model: New Model    Version: 1.0
-- MySQL Workbench Forward Engineering

SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION';

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
DROP SCHEMA IF EXISTS `mydb` ;

-- -----------------------------------------------------
-- Schema mydb
-- -----------------------------------------------------
CREATE SCHEMA IF NOT EXISTS `mydb` DEFAULT CHARACTER SET utf8 ;
USE `mydb` ;

-- -----------------------------------------------------
-- Table `mydb`.`roles`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`roles` ;

CREATE TABLE IF NOT EXISTS `mydb`.`roles` (
  `id` INT NOT NULL,
  `name` VARCHAR(45) NOT NULL,
  PRIMARY KEY (`id`))
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`users`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`users` ;

CREATE TABLE `mydb`.`users` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `user_name` TEXT NOT NULL,
  `email` VARCHAR(45) NOT NULL,
  `password` TEXT NOT NULL,
  `role_id` INT NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE INDEX `idx_email` (`email` ASC) VISIBLE,
  INDEX `fk_roles_users_idx` (`role_id` ASC) VISIBLE,
  CONSTRAINT `fk_roles_users`
    FOREIGN KEY (`role_id`)
    REFERENCES `mydb`.`roles` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;

-- -----------------------------------------------------
-- Table `mydb`.`studies`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`studies` ;

CREATE TABLE IF NOT EXISTS `mydb`.`studies` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `authors` INT NULL,
  `engagement` INT NULL,
  `mentions` INT NULL,
  `status` ENUM("Pending", "Grabbing", "Canceled", "Done") NOT NULL,
  `owner_id` INT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_owner_id` (`owner_id` ASC) VISIBLE,
  CONSTRAINT `fk_studies_users`
    FOREIGN KEY (`owner_id`)
    REFERENCES `mydb`.`users` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`posts`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`posts` ;

CREATE TABLE IF NOT EXISTS `mydb`.`posts` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `url` TEXT NOT NULL,
  `date_of_publication` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `tonality` FLOAT NOT NULL,
  `weight` FLOAT NOT NULL,
  `refers_to` INT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_refers_to` (`refers_to` ASC) VISIBLE,
  CONSTRAINT `fk_posts_studies`
    FOREIGN KEY (`refers_to`)
    REFERENCES `mydb`.`studies` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


-- -----------------------------------------------------
-- Table `mydb`.`authors`
-- -----------------------------------------------------
DROP TABLE IF EXISTS `mydb`.`authors` ;

CREATE TABLE IF NOT EXISTS `mydb`.`authors` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `sex` INT NULL,
  `geolocation` TEXT NULL,
  `age` INT NULL,
  `refers_to` INT NOT NULL,
  PRIMARY KEY (`id`),
  INDEX `idx_refers_to` (`refers_to` ASC) VISIBLE,
  CONSTRAINT `fk_authors_studies`
    FOREIGN KEY (`refers_to`)
    REFERENCES `mydb`.`studies` (`id`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION)
ENGINE = InnoDB;


SET SQL_MODE=@OLD_SQL_MODE;
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;

# RESTfull сервіс для управління даними

entity/User.ts
import { Entity, BaseEntity, Column, PrimaryGeneratedColumn, Unique } from "typeorm";

@Entity("users")
@Unique(["email"])
export class User extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  email: string;

  @Column()
  password: string;

  @Column()
  userName: string;

  @Column()
  roleId: number;
}
controller/UserController.ts
import { Database } from "../database";
import { Repository, QueryFailedError, EntityNotFoundError } from "typeorm";
import { User } from "../entity/User";
import { Request, Response } from "express";

type Handler = (req: Request, res: Response) => Promise<void>;

export class UserController {
  private repository: Repository<User>;

  constructor(database: Database) {
    this.repository = database.getRepository(User);
  }

  errorHandler = (e: Error, res: Response) => {
    switch (e.constructor) {
      case EntityNotFoundError:
        res.status(404).json({
          errorMessage: "Not Found",
        });
        break;

      case QueryFailedError:
        res.status(400).json({
          errorMessage: "Bad request",
        });
        break;
      
      default:
        res.status(500).send({
          errorMessage: "An unknown error",
        });
        break;
    }
  }

  find: Handler = async (_, res) => {
    const users = await this.repository.find();
    res.json(users);
  }
  
  findOne: Handler = async (req, res) => {
    try {
      const user = await this.repository.findOneBy({
        id: Number(req.params.id),
      });
      if (user === null) {
        throw new EntityNotFoundError(User, null);
      }
      res.json(user);
    } catch (e) {
      this.errorHandler(e, res);
    }
  }

  create: Handler = async (req, res) => {
    try {
      const user = this.repository.create(req.body);
      const results = await this.repository.save(user);
      res.json(results);
    } catch (e) {
      this.errorHandler(e, res);
    }
  }


  remove: Handler = async (req, res) => {
    try {
      const { id } = req.params;
      await this.repository.delete(id);
      res.json({
        message: `A user with id ${id} was removed`,
      });
    } catch (e) {
      this.errorHandler(e, res);
    }
  }

  update: Handler = async (req, res) => {
    try {
      const user = await this.repository.findOneBy({
        id: Number(req.params.id),
      });
      this.repository.merge(user, req.body);
      const results = await this.repository.save(user);
      res.send(results);
    } catch (e) {
      this.errorHandler(e, res);
    }
  }
}
database.ts
import { DataSource, EntityTarget } from "typeorm";
import { SnakeNamingStrategy } from "typeorm-naming-strategies";
import { User } from "./entity/User";

export class Database {
  private origin: DataSource;

  constructor() {
    this.origin = new DataSource({
      type: "mysql",
      username: process.env.DB_USER,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
      entities: [User],
      namingStrategy: new SnakeNamingStrategy(),
    });
  }

  async connect() {
    return await this.origin.initialize();
  }

  getRepository<T>(repositoryClass: EntityTarget<T>) {
    return this.origin.getRepository(repositoryClass);
  }
}
index.ts
require("dotenv").config();
import "reflect-metadata";
import * as express from "express";
import { Database } from "./database";
import { UserController } from "./controller/UserController";

(async () => {
  const db = new Database();
  await db.connect();

  const userController = new UserController(db);

  const app = express();
  app.use(express.json());

  app
    .route("/users")
    .get(userController.find)
    .post(userController.create);

  app
    .route("/users/:id")
    .get(userController.findOne)
    .delete(userController.remove)
    .put(userController.update);

  app.listen(80);
})();

Останнє оновлення: 4/27/2023, 5:52:23 PM