diff --git a/modulo6/case4/.gitignore b/modulo6/case4/.gitignore new file mode 100644 index 0000000..1586481 --- /dev/null +++ b/modulo6/case4/.gitignore @@ -0,0 +1,4 @@ +node_modules +.env +build +package-lock.json \ No newline at end of file diff --git a/modulo6/case4/package.json b/modulo6/case4/package.json new file mode 100644 index 0000000..8a27d1a --- /dev/null +++ b/modulo6/case4/package.json @@ -0,0 +1,27 @@ +{ + "name": "backend", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "@types/knex": "^0.16.1", + "cors": "^2.8.5", + "dotenv": "^16.0.1", + "express": "^4.18.1", + "knex": "^2.2.0", + "mysql": "^2.18.1" + }, + "devDependencies": { + "@types/cors": "^2.8.12", + "@types/express": "^4.17.13", + "@types/node": "^18.6.1", + "ts-node-dev": "^2.0.0", + "typescript": "^4.7.4" + } +} diff --git a/modulo6/case4/src/business/ProductBusiness.ts b/modulo6/case4/src/business/ProductBusiness.ts new file mode 100644 index 0000000..e728fe6 --- /dev/null +++ b/modulo6/case4/src/business/ProductBusiness.ts @@ -0,0 +1,57 @@ +import { CustomError } from "../error/CustomError"; +import { Product } from "../model/Product"; +import { ProductDataInterface } from "../model/ProductDataInterface"; +import { GetProductResponse } from "../types/getProductResponse"; +import { RegisterProductInputDTO } from "../types/registerProductInputDTO"; + +export default class ProductBusiness { + constructor ( + private productData: ProductDataInterface + ) {} + + async register (input: RegisterProductInputDTO) { + const { id, name, tags } = input + + const productSameId = await this.productData.getProductById(id) + if (productSameId) { + throw new CustomError(409, "Product with this id already exists") + } + const productSameName = await this.productData.getProductByName(name) + if (productSameName) { + throw new CustomError(409, "Product with this name already exists") + } + + const newProduct = new Product(id, name, tags) + + await this.productData.insert(newProduct) + + return name + } + + async getById (id: number) { + + if (!id || isNaN(id)) { + throw new CustomError(417, "Invalid id") + } + + const result = await this.productData.getProductById(id) + if (!result) { + throw new CustomError(404, "Product not found") + } + + return result + } + + async search (searchInput: string) { + let result: GetProductResponse[] + if (!searchInput) { + result = await this.productData.getAllProducts() + + return result + } + + result = await this.productData.searchProducts(searchInput) + + return result + } +} \ No newline at end of file diff --git a/modulo6/case4/src/controller/ProductController.ts b/modulo6/case4/src/controller/ProductController.ts new file mode 100644 index 0000000..3a71879 --- /dev/null +++ b/modulo6/case4/src/controller/ProductController.ts @@ -0,0 +1,62 @@ +import { Request, Response } from "express"; +import ProductBusiness from "../business/ProductBusiness"; +import { RegisterProductInputDTO } from "../types/registerProductInputDTO"; + +export default class ProductController { + constructor ( + private productBusiness: ProductBusiness + ) {} + + register = async (req: Request, res: Response) => { + const {id, name, tags} = req.body + + const input: RegisterProductInputDTO = { + id, + name, + tags + } + try { + const productName = await this.productBusiness.register(input) + + res.status(201).send(`${productName} registered successfully`) + + } catch (error) { + if (error instanceof Error) { + return res.status(400).send(error.message) + } + res.status(500).send("Register error.") + } + } + + getById = async (req: Request, res: Response) => { + const id = Number(req.params.id) + + try { + const product = await this.productBusiness.getById(id) + + res.send({ product }) + + } catch (error) { + if (error instanceof Error) { + return res.status(400).send(error.message) + } + res.status(500).send("Register error.") + } + } + + search = async (req: Request, res: Response) => { + const searchInput = req.query.search as string + + try { + const searchResult = await this.productBusiness.search(searchInput) + + res.send({ productsFromSearch: searchResult }) + + } catch (error) { + if (error instanceof Error) { + return res.status(400).send(error.message) + } + res.status(500).send("Register error.") + } + } +} \ No newline at end of file diff --git a/modulo6/case4/src/data/BaseDatabase.ts b/modulo6/case4/src/data/BaseDatabase.ts new file mode 100644 index 0000000..7511e05 --- /dev/null +++ b/modulo6/case4/src/data/BaseDatabase.ts @@ -0,0 +1,17 @@ +import knex from "knex"; +import dotenv from "dotenv" +dotenv.config() + +export default abstract class BaseDatabase { + protected connection = knex({ + client: 'mysql', + connection: { + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_SCHEMA, + port: 3306, + multipleStatements: true + } + }) +} \ No newline at end of file diff --git a/modulo6/case4/src/data/ProductData.ts b/modulo6/case4/src/data/ProductData.ts new file mode 100644 index 0000000..9e70c9b --- /dev/null +++ b/modulo6/case4/src/data/ProductData.ts @@ -0,0 +1,81 @@ +import { Product } from "../model/Product"; +import { ProductDataInterface } from "../model/ProductDataInterface"; +import { productTableName } from "../model/TableNames"; +import { GetProductResponse } from "../types/getProductResponse"; +import BaseDatabase from "./BaseDatabase"; + +export default class ProductData extends BaseDatabase implements ProductDataInterface { + private TABLE_NAME = productTableName + insert = async (product: Product) => { + try { + await this.connection(this.TABLE_NAME) + .insert(product) + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } else { + throw new Error("Database error.") + } + } + } + + getProductByName = async (name: string) => { + try { + const queryResult: GetProductResponse[] = await this.connection(this.TABLE_NAME) + .where({ name }) + + return queryResult[0] + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } else { + throw new Error("Database error.") + } + } + } + + getProductById = async (id: number) => { + try { + const queryResult: GetProductResponse[] = await this.connection(this.TABLE_NAME) + .where({ id }) + + return queryResult[0] + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } else { + throw new Error("Database error.") + } + } + } + + searchProducts = async (search: string) => { + try { + const queryResult: GetProductResponse[] = await this.connection(this.TABLE_NAME) + .whereLike('name', `%${search}%`) + .orWhereLike('tag', `%${search}%`) + + return queryResult + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } else { + throw new Error("Database error.") + } + } + } + + getAllProducts = async () => { + try { + const queryResult: GetProductResponse[] = await this.connection(this.TABLE_NAME) + + return queryResult + } catch (error) { + if (error instanceof Error) { + throw new Error(error.message) + } else { + throw new Error("Database error.") + } + } + } +} \ No newline at end of file diff --git a/modulo6/case4/src/error/CustomError.ts b/modulo6/case4/src/error/CustomError.ts new file mode 100644 index 0000000..280f738 --- /dev/null +++ b/modulo6/case4/src/error/CustomError.ts @@ -0,0 +1,12 @@ +export class CustomError extends Error { + + protected statusCode: number + + constructor ( + statusCode: number = 400, + message: string + ) { + super(message) + this.statusCode = statusCode + } +} \ No newline at end of file diff --git a/modulo6/case4/src/index.ts b/modulo6/case4/src/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/modulo6/case4/src/model/Product.ts b/modulo6/case4/src/model/Product.ts new file mode 100644 index 0000000..0dec3ec --- /dev/null +++ b/modulo6/case4/src/model/Product.ts @@ -0,0 +1,7 @@ +export class Product { + constructor ( + private id: number, + private name: string, + private tags: string[] + ) {} +} \ No newline at end of file diff --git a/modulo6/case4/src/model/ProductDataInterface.ts b/modulo6/case4/src/model/ProductDataInterface.ts new file mode 100644 index 0000000..544b402 --- /dev/null +++ b/modulo6/case4/src/model/ProductDataInterface.ts @@ -0,0 +1,14 @@ +import { GetProductResponse } from "../types/getProductResponse" +import { Product } from "./Product" + +export interface ProductDataInterface { + insert: (product: Product) => Promise + + getProductByName: (name: string) => Promise + + getProductById: (id: number) => Promise + + searchProducts: (search: string) => Promise + + getAllProducts: () => Promise +} \ No newline at end of file diff --git a/modulo6/case4/src/model/TableNames.ts b/modulo6/case4/src/model/TableNames.ts new file mode 100644 index 0000000..e077d2a --- /dev/null +++ b/modulo6/case4/src/model/TableNames.ts @@ -0,0 +1 @@ +export const productTableName = 'products_amaro' \ No newline at end of file diff --git a/modulo6/case4/src/model/error/CustomError.ts b/modulo6/case4/src/model/error/CustomError.ts new file mode 100644 index 0000000..280f738 --- /dev/null +++ b/modulo6/case4/src/model/error/CustomError.ts @@ -0,0 +1,12 @@ +export class CustomError extends Error { + + protected statusCode: number + + constructor ( + statusCode: number = 400, + message: string + ) { + super(message) + this.statusCode = statusCode + } +} \ No newline at end of file diff --git a/modulo6/case4/src/types/getProductResponse.ts b/modulo6/case4/src/types/getProductResponse.ts new file mode 100644 index 0000000..82d9585 --- /dev/null +++ b/modulo6/case4/src/types/getProductResponse.ts @@ -0,0 +1,5 @@ +export type GetProductResponse = { + id: number, + name: string, + tags: string[] +} \ No newline at end of file diff --git a/modulo6/case4/src/types/registerProductInputDTO.ts b/modulo6/case4/src/types/registerProductInputDTO.ts new file mode 100644 index 0000000..f920366 --- /dev/null +++ b/modulo6/case4/src/types/registerProductInputDTO.ts @@ -0,0 +1,5 @@ +export type RegisterProductInputDTO = { + id: number, + name: string, + tags: string[] +} \ No newline at end of file diff --git a/modulo6/case4/tsconfig.json b/modulo6/case4/tsconfig.json new file mode 100644 index 0000000..5aa4d5f --- /dev/null +++ b/modulo6/case4/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", /* Specify ECMAScript target version */ + "module": "commonjs", /* Specify module code generation */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + "rootDir": "./", /* Specify the root directory of input files. */ + "removeComments": true, /* Do not emit comments to output. */ + "noImplicitAny": true, /* Raise error on declarations with an implied 'any' type. */ + "esModuleInterop": true, /*Pra quando da problema importando cors, express no topo do arquivo*/ + "resolveJsonModule": true + } + } \ No newline at end of file diff --git a/modulo6/exercicios-logica/checa-parenteses/package.json b/modulo6/exercicios-logica/checa-parenteses/package.json new file mode 100644 index 0000000..1780b3f --- /dev/null +++ b/modulo6/exercicios-logica/checa-parenteses/package.json @@ -0,0 +1,13 @@ +{ + "name": "checa-parenteses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "tsc && node ./build/index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/modulo6/exercicios-logica/checa-parenteses/src/index.ts b/modulo6/exercicios-logica/checa-parenteses/src/index.ts new file mode 100644 index 0000000..67e0da9 --- /dev/null +++ b/modulo6/exercicios-logica/checa-parenteses/src/index.ts @@ -0,0 +1,64 @@ +function checaParenteses(str: string) { + let output = true + const parenteses = [] + for (let char of str) { + if (char === '(' || char === '[' || char === '{') { + parenteses.push(char) + } + if (char === ')' || char === ']' || char === '}') { + let parenteseFechado = false + for (let i = parenteses.length - 1; i >= 0; i--) { + switch (char) { + case ')': + if (parenteses[i] === '(') { + parenteseFechado = true + parenteses.splice(i, 1) + i = -1 + } + if (parenteses[i] === '[' || parenteses[i] === '{') { + output = false + i = -1 + } + break + case ']': + if (parenteses[i] === '[') { + parenteseFechado = true + parenteses.splice(i, 1) + i = -1 + } + if (parenteses[i] === '(' || parenteses[i] === '{') { + output = false + i = -1 + } + break + case '}': + if (parenteses[i] === '{') { + parenteseFechado = true + parenteses.splice(i, 1) + i = -1 + } + if (parenteses[i] === '[' || parenteses[i] === '(') { + output = false + i = -1 + } + break + + } + + } + if (!parenteseFechado) { + output = false + } + } + } + if (parenteses.length) { + output = false + } + return output +} + +console.log(checaParenteses("()")); +console.log(checaParenteses("()[]{}")); +console.log(checaParenteses("(]")); +console.log(checaParenteses("([)]")); +console.log(checaParenteses("{[]}")); diff --git a/modulo6/exercicios-logica/checa-parenteses/tsconfig.json b/modulo6/exercicios-logica/checa-parenteses/tsconfig.json new file mode 100644 index 0000000..91829ea --- /dev/null +++ b/modulo6/exercicios-logica/checa-parenteses/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", /* Specify ECMAScript target version */ + "module": "commonjs", /* Specify module code generation */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. */ + "removeComments": true, /* Do not emit comments to output. */ + "noImplicitAny": true, /* Raise error on declarations with an implied 'any' type. */ + "esModuleInterop": true, /*Pra quando da problema importando cors, express no topo do arquivo*/ + "resolveJsonModule": true + } + } \ No newline at end of file diff --git a/modulo6/exercicios-logica/numero-solitario/package.json b/modulo6/exercicios-logica/numero-solitario/package.json new file mode 100644 index 0000000..1780b3f --- /dev/null +++ b/modulo6/exercicios-logica/numero-solitario/package.json @@ -0,0 +1,13 @@ +{ + "name": "checa-parenteses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "tsc && node ./build/index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/modulo6/exercicios-logica/numero-solitario/src/index.ts b/modulo6/exercicios-logica/numero-solitario/src/index.ts new file mode 100644 index 0000000..e6e970c --- /dev/null +++ b/modulo6/exercicios-logica/numero-solitario/src/index.ts @@ -0,0 +1,16 @@ +function numeroSolitario (arr: number[]) { + const numeros: number[] = [] + for (let num of arr) { + const i = numeros.indexOf(num) + if (i < 0) { + numeros.push(num) + } else { + numeros.splice(i, 1) + } + } + + return numeros[0] +} + +console.log(numeroSolitario([2,2,1])); +console.log(numeroSolitario([4,1,2,1,2])); diff --git a/modulo6/exercicios-logica/numero-solitario/tsconfig.json b/modulo6/exercicios-logica/numero-solitario/tsconfig.json new file mode 100644 index 0000000..91829ea --- /dev/null +++ b/modulo6/exercicios-logica/numero-solitario/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", /* Specify ECMAScript target version */ + "module": "commonjs", /* Specify module code generation */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. */ + "removeComments": true, /* Do not emit comments to output. */ + "noImplicitAny": true, /* Raise error on declarations with an implied 'any' type. */ + "esModuleInterop": true, /*Pra quando da problema importando cors, express no topo do arquivo*/ + "resolveJsonModule": true + } + } \ No newline at end of file diff --git a/modulo6/exercicios-logica/prefixo-comum/package.json b/modulo6/exercicios-logica/prefixo-comum/package.json new file mode 100644 index 0000000..1780b3f --- /dev/null +++ b/modulo6/exercicios-logica/prefixo-comum/package.json @@ -0,0 +1,13 @@ +{ + "name": "checa-parenteses", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "tsc && node ./build/index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/modulo6/exercicios-logica/prefixo-comum/src/index.ts b/modulo6/exercicios-logica/prefixo-comum/src/index.ts new file mode 100644 index 0000000..cbea49f --- /dev/null +++ b/modulo6/exercicios-logica/prefixo-comum/src/index.ts @@ -0,0 +1,27 @@ +function prefixoComum (arr: string[]) { + let result = '' + let limite = Infinity + for (let str of arr) { + limite = Math.min(limite, str.length) + } + for (let i = 0; i < limite; i++) { + const char = arr[0][i] + let prefixoValido = true + for (let str of arr) { + if (str[i] !== char) { + prefixoValido = false + } + } + if (prefixoValido) { + result = result + char + } else { + break + } + } + + return result +} + +console.log(prefixoComum(["flower","flow","flight"])); +console.log(prefixoComum(["dog","racecar","car"])); +console.log(prefixoComum(["coracao","cor","corona","coreia"])); diff --git a/modulo6/exercicios-logica/prefixo-comum/tsconfig.json b/modulo6/exercicios-logica/prefixo-comum/tsconfig.json new file mode 100644 index 0000000..91829ea --- /dev/null +++ b/modulo6/exercicios-logica/prefixo-comum/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", /* Specify ECMAScript target version */ + "module": "commonjs", /* Specify module code generation */ + "sourceMap": true, /* Generates corresponding '.map' file. */ + "outDir": "./build", /* Redirect output structure to the directory. */ + "rootDir": "./src", /* Specify the root directory of input files. */ + "removeComments": true, /* Do not emit comments to output. */ + "noImplicitAny": true, /* Raise error on declarations with an implied 'any' type. */ + "esModuleInterop": true, /*Pra quando da problema importando cors, express no topo do arquivo*/ + "resolveJsonModule": true + } + } \ No newline at end of file