Repository: nodejsbrazil/cursonodebr01
Branch: master
Commit: 7dcc09f3f2c9
Files: 370
Total size: 359.9 KB
Directory structure:
gitextract_eoxbnz9h/
├── .gitignore
├── README.md
├── module-00 - intro/
│ ├── 1. npm/
│ │ └── scripts.sh
│ └── 2.nodejs/
│ ├── app/
│ │ ├── index.js
│ │ └── package.json
│ └── scripts.sh
├── module-01 - sincronia de funcoes/
│ ├── 1.callbacks/
│ │ └── app/
│ │ ├── index.js
│ │ └── package.json
│ ├── 2.promise/
│ │ └── app/
│ │ ├── index.js
│ │ └── package.json
│ ├── 3. async-await/
│ │ └── app/
│ │ ├── index.js
│ │ └── package.json
│ ├── 4. event-emitter/
│ │ └── app/
│ │ ├── index.js
│ │ └── package.json
│ └── 5. observable/
│ ├── 1.simple/
│ │ └── index.js
│ └── 2. rxjs app/
│ ├── index.js
│ ├── package.json
│ ├── temp/
│ │ └── teste.1.json
│ └── teste.json
├── module-02 - manipulacao de listas/
│ ├── 1.for-forin-forof.js
│ ├── 2.map.js
│ ├── 3.filter.js
│ ├── 4.reduce.js
│ ├── README.md
│ ├── package.json
│ └── service.js
├── module-03 - Introdução a testes automatizados/
│ ├── README.md
│ ├── package.json
│ ├── service.js
│ └── test.js
├── module-04 - ferramentas de linha de comando/
│ ├── cli.js
│ ├── database.js
│ ├── heroes.json
│ ├── heroi.js
│ ├── package.json
│ └── test.js
├── module-05 - nosso projeto multi-database/
│ ├── README.md
│ ├── index.js
│ ├── package.json
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ └── src/
│ ├── db/
│ │ └── strategies/
│ │ ├── base/
│ │ │ ├── contextStrategy.js
│ │ │ └── interfaceDb.js
│ │ ├── mongoDbStrategy.js
│ │ └── postgresStrategy.js
│ └── example1.js
├── module-06 - postgres e modelos relacionais/
│ ├── README.md
│ ├── index.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── postgresStrategy.test.js
│ ├── scripts/
│ │ └── postgres.sql
│ └── src/
│ ├── db/
│ │ └── strategies/
│ │ ├── base/
│ │ │ ├── contextStrategy.js
│ │ │ └── interfaceDb.js
│ │ ├── mongoDbStrategy.js
│ │ └── postgresSQLStrategy.js
│ └── example1.js
├── module-07 - mongodb e bancos nao-relacionais/
│ ├── README.md
│ ├── index.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongoDbStrategy.js
│ │ │ └── postgresSQLStrategy.js
│ │ └── example1.js
│ └── tests/
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.0 - organização de bases/
│ ├── README.md
│ ├── index.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ └── example1.js
│ └── tests/
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.1 - hapi - estrutura e listar/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.2 - hapi - cadastrar/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.3 - hapi - joi/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.4 - hapi - atualizar/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.5 - hapi - remover/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.6 - hapi - swagger/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.7 - hapi - jwt/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── authRoutes.js
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── auth.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.8 - hapi - jwt-herois/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroiSchema.js
│ │ ├── example1.js
│ │ └── routes/
│ │ ├── authRoutes.js
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── auth.test.js
│ ├── mongodbStrategy.test.js
│ └── postgresStrategy.test.js
├── module-08.9 - hapi - user-validation/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ ├── heroiSchema.js
│ │ │ └── userSchema.js
│ │ ├── example1.js
│ │ ├── helpers/
│ │ │ └── passwordHelper.js
│ │ └── routes/
│ │ ├── authRoutes.js
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── auth.test.js
│ ├── mongodbStrategy.test.js
│ ├── passwordHelper.test.js
│ └── postgresStrategy.test.js
├── module-09 - enviroment/
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ ├── heroiSchema.js
│ │ │ └── userSchema.js
│ │ ├── example1.js
│ │ ├── helpers/
│ │ │ └── passwordHelper.js
│ │ └── routes/
│ │ ├── authRoutes.js
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── auth.test.js
│ ├── mongodbStrategy.test.js
│ ├── passwordHelper.test.js
│ └── postgresStrategy.test.js
├── module-10 - production-mongodb-postgres/
│ ├── .gitignore
│ ├── Procfile
│ ├── README.md
│ ├── api-example.js
│ ├── api.js
│ ├── mongodb-example.js
│ ├── package.json
│ ├── postgres-example.js
│ ├── scripts/
│ │ ├── mongodb.sh
│ │ └── postgres.sql
│ ├── server.js
│ ├── src/
│ │ ├── db/
│ │ │ └── strategies/
│ │ │ ├── base/
│ │ │ │ ├── contextStrategy.js
│ │ │ │ └── interfaceDb.js
│ │ │ ├── mongodb/
│ │ │ │ ├── mongoDbStrategy.js
│ │ │ │ └── schemas/
│ │ │ │ └── heroSchema.js
│ │ │ └── postgres/
│ │ │ ├── postgresSQLStrategy.js
│ │ │ └── schemas/
│ │ │ ├── heroiSchema.js
│ │ │ └── userSchema.js
│ │ ├── example1.js
│ │ ├── helpers/
│ │ │ └── passwordHelper.js
│ │ └── routes/
│ │ ├── authRoutes.js
│ │ ├── base/
│ │ │ └── baseRoute.js
│ │ └── heroRoutes.js
│ └── tests/
│ ├── apiHeroes.test.js
│ ├── auth.test.js
│ ├── mongodbStrategy.test.js
│ ├── passwordHelper.test.js
│ └── postgresStrategy.test.js
└── module-11 - istanbul/
├── .gitignore
├── Procfile
├── README.md
├── api-example.js
├── api.js
├── mongodb-example.js
├── package.json
├── postgres-example.js
├── scripts/
│ ├── mongodb.sh
│ └── postgres.sql
├── server.js
├── src/
│ ├── db/
│ │ └── strategies/
│ │ ├── base/
│ │ │ ├── contextStrategy.js
│ │ │ └── interfaceDb.js
│ │ ├── mongodb/
│ │ │ ├── mongoDbStrategy.js
│ │ │ └── schemas/
│ │ │ └── heroSchema.js
│ │ └── postgres/
│ │ ├── postgresSQLStrategy.js
│ │ └── schemas/
│ │ ├── heroiSchema.js
│ │ └── userSchema.js
│ ├── example1.js
│ ├── helpers/
│ │ └── passwordHelper.js
│ └── routes/
│ ├── authRoutes.js
│ ├── base/
│ │ └── baseRoute.js
│ ├── heroRoutes.js
│ └── utilRoutes.js
└── tests/
├── apiHeroes.test.js
├── auth.test.js
├── mongodbStrategy.test.js
├── passwordHelper.test.js
└── postgresStrategy.test.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
node_modules
================================================
FILE: README.md
================================================
# Bem vindo ao Curso NodeBR
Inscrições: [https://treinamento.nodebr.org/](https://treinamento.nodebr.org/)
## SOBRE O TREINAMENTO
Varrendo a internet, encontramos diversos treinamentos sobre **Node.js** e **Javascript**. Mas na maioria das vezes estes conteúdos **são focados na mesma coisa**! A grande maioria fala sobre a Stack **MEAN** (MongoDB, Express.js, Angular.js e Node.js), programação para Web ou apenas **simples CRUDs** (as operações básicas de sistemas: Cadastrar, Listar, Atualizar e Remover), coisas que para **estudos** funcionam muito bem, mas a **realidade** no dia a dia de desenvolvimento de **aplicações** focado em **produção** é um pouco **diferente**.
Este treinamento foi **desenvolvido** sob medida **baseado** em uma pesquisa sobre o que a **comunidade brasileira mais necessita**, suas principais **dificuldades** e **desafios**. Neste curso você aprenderá desde o básico de Javascript, ciclo de vida, manipulação de listas ao desenvolvimento real de aplicações em ambiente de produção. Na prática você também aprenderá conceitos sobre desenvolvimento orientado a testes, autenticação, autorização, documentação de serviços e gerenciamento de variáveis de ambiente (environments) de aplicações.
## INSTRUTOR
### [Erick Wendel](https://twitter.com/erickwendel_)
Erick Wendel is a Speaker, Software Consultant and community Co-organizer on Brazil. Named by Microsoft as Most Valuable Professional, and by Google as Google Developer Expert a specialist in Node.js, and Javascript Applications. He is Software Independent Architect where help companies to make better and cheaper applications using Serverless, Container based applications, and Hybrid Cloud solutions. He has experience speaking and teaching on the biggest conferences in Brazil and Americas, working as voluntary Leader of NodeBR, Javascript São Paulo and Nerdzão Communities.
Twitter: [@erickwendel_](https://twitter.com/erickwendel_)
Linkedin: [br.linkedin.com/in/erickwendel](http://br.linkedin.com/in/erickwendel)
Github: [github.com/erickwendel](https://github.com/erickwendel)
Facebook: [fb.com/page.erickwendel](https://fb.com/page.erickwendel)
Website: [erickwendel.com](http://erickwendel.com/)
## CONTEÚDO
### Módulo 0 Introdução ao Curso
- Introdução ao Curso e Objetivos
- Tópicos abordados - O que aprenderei ?
- Instalação e Configuração
- Introdução ao Node.js
- Conhecendo o gerenciador de pacotes NPM
- Começando um projeto Node.js
### Módulo 1 Sincronia de Funções Javascript
- Introdução ao Capitulo
- Entendendo o ciclo de vida de aplicações Javascript
- Trabalhando com Callbacks
- Introdução a Promises
- Refatorando Callbacks para Promises
- Introdução a resolução de Promises com async/await
- Resolução de promises com Async/Await
- Introdução à manipulação de eventos com EventEmitter
- Trabalhando com Eventos com a classe EventEmitter
### Módulo 2 Manipulação de Listas
- Introdução ao Capitulo
- Manipulando listas com For/ForIn/ForOf
- Criando nosso proprio Array.Map
- Criando nosso proprio Array.Filter
- Criando nosso proprio Array.Reduce
### Módulo 3 Introdução a desenvolvimento de testes automatizados
- Introdução a desenvolvimento de testes automatizados em Javascript
- Ambiente e configuração do ciclo de testes
### Módulo 4 Node.js além da Web - Criando ferramentas de linha de comando
- Introdução ao Capítulo
- Manipulando arquivos - CREATE
- Manipulando arquivos - READ
- Manipulando arquivos - UPDATE
- Manipulando arquivos - DELETE
- Criando ferramentas de linha de comando com Commander
### Módulo 5 Bancos de Dados - Nosso projeto Multi-banco de dados
- Criando projetos multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
- Design Patterns - Strategy
- Demonstração multi datasources com strategy design pattern
### Módulo 6 Introdução ao Postgres e Bancos Relacionais
- Introdução ao Postgres e Bancos Relacionais
- Postgres - Operadores e conexão
- Conhecendo o Sequelize
- Cadastrando Heróis - CREATE
- Listando Heróis - READ
- Atualizando Heróis - UPDATE
- Removendo Heróis - DELETE
### Módulo 7 MongoDB e Bancos Não-Relacionais (NoSQL)
- Introdução ao MongoDB e Bancos Não-Relacionais (NoSQL)
- Operadores e conexão
- Conhecendo o Mongoose
- Cadastrando Heróis - CREATE
- Listando Heróis - READ
- Atualizando Heróis - UPDATE
- Removendo Heróis - DELETE
### Módulo 8 Refatorando nosso projeto para bancos de dados multi-schemas
- Refatorando a estratégia de MongoDB para multi-schemas
- Refatorando a estratégia de Postgres para multi-schemas
### Módulo 9 Node.js e Web Services - Criando serviços profissionais com Hapi.js
- Introdução ao Capítulo
- Conhecendo o Módulo HTTP
- Introdução ao Hapi.js
- Criando de estrutura para criação de APIs com Hapi.js
- Entendendo o padrão RestFul para desenvolvimento de APIs
- Cadastrando Heróis - POST
- Listando Heróis - GET
- Atualizando Heróis - PATCH / PUT
- Removendo Heróis - DELETE
- Código fonte do capítulo
### Módulo 10 Documentação de Serviços com Swagger
- Adicionando Swagger ao nosso Serviço
### Módulo 11 Autenticação com Json Web Token
- Introdução ao Capitulo
- Como funciona o Json Web Token?
- Configurando o JWT - plugins, testes e rota de login
- Adicionando Hapi-JWT ao nosso Serviço de herois
- Criando o modulo de autenticação de usuarios e hash de senha com bcrypt
### Módulo 12 Publicação de serviços na Web
- Introdução ao Capitulo
- Trabalhando com multi-environments (development, production)
- Publicação de nossos serviços gratuitamente com Heroku & Heroku toolbelt
- MongoDB online e gratuito com Mongo Lab
- Postgres Gratuito no Heroku
- Trabalhando com PM2 para gerência de apps
- Expondo cobertura de código com istanbul
### Módulo 13 Próximos passos
- O que aprender?
## Certificado
O melhor é que você ainda ganha este lindo certificado ao fim do treinamento! Vai ficar de fora?
================================================
FILE: module-00 - intro/1. npm/scripts.sh
================================================
instalação
npm
http://npmjs.com/
================================================
FILE: module-00 - intro/2.nodejs/app/index.js
================================================
class HeroiCRUD {
constructor() {
this.herois = []
}
cadastrar(heroi) {
this.herois.push(heroi)
}
listar() {
return this.herois;
}
obterHeroiPorId(id) {
for (let posicao = 0; posicao < this.herois.length; ++posicao) {
const heroi = this.herois[posicao];
if (heroi.id !== id) continue;
return {
heroi,
posicao
};
break;
}
throw new Error('Heroi não encontrado!')
}
atualizar(id, novoHeroi) {
const {
heroi,
posicao
} = this.obterHeroiPorId(id);
this.herois[posicao] = Object.assign({}, heroi, novoHeroi)
}
remover(id) {
const {
posicao
} = this.obterHeroiPorId(id)
this.herois.pop(posicao)
}
}
(function main() {
try {
const heroiCrud = new HeroiCRUD()
// cadastrar
heroiCrud.cadastrar({
id: 1,
name: 'Erick'
})
heroiCrud.cadastrar({
id: 2,
name: 'Wendel'
})
heroiCrud.cadastrar({
id: 3,
name: 'Silva'
})
console.log('listar', heroiCrud.listar())
//atualizar
heroiCrud.atualizar(1, {
name: 'Flash'
})
const {
heroi
} = heroiCrud.obterHeroiPorId(1)
console.log('heroi atualizado', heroi)
// remover
heroiCrud.remover(2)
console.log('removido', heroiCrud.listar())
} catch (error) {
console.error('Erro!', error.message)
}
})()
================================================
FILE: module-00 - intro/2.nodejs/app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "erickwendel",
"license": "ISC"
}
================================================
FILE: module-00 - intro/2.nodejs/scripts.sh
================================================
----
npm init
npm init -y
npm install
npm install -g modulo
npm install --save modulo
npm install --save-dev modulo
node -e "1+1" -p
================================================
FILE: module-01 - sincronia de funcoes/1.callbacks/app/index.js
================================================
function obterPessoa(id, callback) {
setTimeout(() => {
return callback(null, {
nome: 'Erick',
id: 2,
});
}, 500);
}
function obterEndereco(pessoaId, callback) {
setTimeout(() => {
return callback(null, {
endereco: 'Av paulista, 22',
id: 3,
});
});
}
function obterTelefone(pessoaId, callback) {
setTimeout(() => {
return callback(null, {
telefone: '11969803388',
id: 22,
});
});
}
(function main() {
obterPessoa(2, (error1, result1) => {
obterEndereco(result1.id, (error2, result2) => {
obterTelefone(result1.id, (error3, result3) => {
console.log(`
Nome: ${result1.nome},
Telefone: ${result3.telefone},
Endereco: ${result2.endereco}
`);
});
});
});
})();
================================================
FILE: module-01 - sincronia de funcoes/1.callbacks/app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
================================================
FILE: module-01 - sincronia de funcoes/2.promise/app/index.js
================================================
function obterPessoa(id, callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
nome: 'Erick',
id: 2,
});
}, 500);
});
}
function obterEndereco(pessoaId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
endereco: 'Av paulista, 22',
id: 3,
});
});
});
}
function obterTelefone(pessoaId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
telefone: '11969803388',
id: 22,
});
});
});
}
(function main() {
Promise.resolve()
.then(_ => obterPessoa(2))
.then(pessoa => {
return obterTelefone(pessoa.id).then(({ telefone }) => {
return Object.assign({}, pessoa, { telefone });
});
})
.then(pessoa => {
return obterEndereco(pessoa.id).then(({ endereco }) => {
return Object.assign({}, pessoa, { endereco });
});
})
.then(pessoa => {
console.log(`
Nome: ${pessoa.nome},
Telefone: ${pessoa.telefone},
Endereco: ${pessoa.endereco}
`);
})
.catch(error => {
console.error('Deu ruim', error);
});
})();
================================================
FILE: module-01 - sincronia de funcoes/2.promise/app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
================================================
FILE: module-01 - sincronia de funcoes/3. async-await/app/index.js
================================================
function obterPessoa(id, callback) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
nome: 'Erick',
id: 2,
});
}, 500);
});
}
function obterEndereco(pessoaId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
endereco: 'Av paulista, 22',
id: 3,
});
});
});
}
function obterTelefone(pessoaId) {
return new Promise((resolve, reject) => {
setTimeout(() => {
return resolve({
telefone: '11969803388',
id: 22,
});
});
});
}
(async function main() {
const pessoa = await obterPessoa(2);
const { telefone } = await obterTelefone(pessoa.id);
const { endereco } = await obterEndereco(pessoa.id);
console.log(`
Nome: ${pessoa.nome},
Telefone: ${telefone},
Endereco: ${endereco}
`);
})();
================================================
FILE: module-01 - sincronia de funcoes/3. async-await/app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
================================================
FILE: module-01 - sincronia de funcoes/4. event-emitter/app/index.js
================================================
const EventEmitter = require('events');
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
console.log('an event occurred!');
});
myEmitter.emit('event');
const stdin = process.openStdin();
stdin.addListener('data', function(d) {
// note: d is an object, and when converted to a string it will
// end with a linefeed. so we (rather crudely) account for that
// with toString() and then trim()
console.log('you entered: [' + d.toString().trim() + ']');
});
================================================
FILE: module-01 - sincronia de funcoes/4. event-emitter/app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC"
}
================================================
FILE: module-01 - sincronia de funcoes/5. observable/1.simple/index.js
================================================
class NotImplementedException extends Error {
constructor(message) {
this.message = message || "Error, this method has to be implemented"
}
}
class ISubject {
subscribe(observer) {
throw new NotImplementedException()
}
unsubscribe(observer) {
throw new NotImplementedException()
}
notify() {
throw new NotImplementedException()
}
}
class Observer {
constructor(name) {
this.observerName = name
this.update = this._update
}
_update(newValue, oldValue) {
console.log(`${this.observerName}, the value ${oldValue} was changed to ${newValue}`)
}
}
class Subject extends ISubject {
constructor() {
super()
this.observers = []
const inventory = {
set: (target, propertyKey, newValue) => {
this.notify(newValue, target[propertyKey])
target[propertyKey] = newValue
return true
}
}
this._item = new Proxy({
count: 0,
}, inventory)
}
next(value) {
this._item.count = value;
}
notify(newValue, oldValue) {
this.observers.forEach(observer => observer.update(newValue, oldValue))
}
unsubscribe(observer) {
const index = this.observers.indexOf(observer)
console.log(`x${this.observers[index].observerName} will not notified anymore`)
this.observers.splice(index, 1)
}
subscribe(observable) {
this.observers.push(observable)
}
}
// behavioral pattern
/**
* We can say that observer is
* something (objects in case of OOPS) which is looking upon (observing)
* other object(s). Observer pattern is popularly known to be based on
* "The Hollywood Principle" which says- "Don’t call us, we will call you."
* Pub-Sub (Publisher-Subscriber) is yet another popular nickname given to
* Observer pattern.
The online electronic store is going to be the subject.
Whenever the subject would have any addition in its inventory,
the observers (customers/users) who have subscribed to store notifications
would be notified through email
*/
(async function main() {
const subject = new Subject()
// Observer1 takes a subscription to the store
const observer1 = new Observer("Erick")
subject.subscribe(observer1)
// Observer2 also subscribes to the store
const observer2 = new Observer("Camilla")
subject.subscribe(observer2)
subject.next(1);
// Observer1 unsubscribes
subject.unsubscribe(observer1)
// Observer3 subscribes to notifications.
subject.subscribe(new Observer("Amanda"))
subject.next(2);
})()
================================================
FILE: module-01 - sincronia de funcoes/5. observable/2. rxjs app/index.js
================================================
const Rx = require('rxjs');
const { switchMap, map, reduce, filter, from } = require('rxjs/operators');
const fs = require('fs');
const watch = dir =>
Rx.Observable.create(observer => {
fs.watch(dir, (eventType, filename) => {
return observer.next({
eventType,
filename: `${dir}/${filename.toString()}`,
});
});
});
const read = filename => Rx.bindNodeCallback(fs.readFile)(filename);
watch('./temp')
.pipe(
map(item => {
console.log(item);
return item;
}),
)
.pipe(switchMap(e => read(e.filename)), map(JSON.parse))
.pipe(switchMap(e => Rx.from(e)))
.subscribe(
e =>
console.log(`
Nome: ${e.nome},
Idade: ${e.idade}
`),
error => console.error('deu ruim', error),
);
================================================
FILE: module-01 - sincronia de funcoes/5. observable/2. rxjs app/package.json
================================================
{
"name": "app",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"rxjs": "^6.2.0"
}
}
================================================
FILE: module-01 - sincronia de funcoes/5. observable/2. rxjs app/temp/teste.1.json
================================================
[
{
"nome": "Erick",
"idade": 22
},
{
"nome": "Wendel",
"idade": 25
}
]
================================================
FILE: module-01 - sincronia de funcoes/5. observable/2. rxjs app/teste.json
================================================
[
{
"nome": "Maria",
"idade": 22
},
{
"nome": "Laisa",
"idade": 23
}
]
================================================
FILE: module-02 - manipulacao de listas/1.for-forin-forof.js
================================================
const { obterPessoas } = require('./service');
//
(async main => {
const result = await obterPessoas('a');
const names = [];
// for (let i = 0; i <= result.results.length - 1; i++) {
// const pessoa = result.results[i];
// names.push(pessoa.name);
// }
// console.log('names', names);
// for (let i in result.results) {
// const pessoa = result.results[i];
// names.push(pessoa.name);
// }
// console.log('names', names);
for (pessoa of result.results) {
names.push(pessoa.name);
}
console.log('names', names);
})();
================================================
FILE: module-02 - manipulacao de listas/2.map.js
================================================
const { obterPessoas } = require('./service');
//Criando nosso próprio Map
Array.prototype.meuMap = function(callback) {
const novoArrayMapeado = [];
for (let indice = 0; indice <= this.length - 1; indice++)
novoArrayMapeado.push(callback(this[indice], indice));
return novoArrayMapeado;
};
//
(async main => {
const result = await obterPessoas('a');
// map tradicional
// const names = result.results.map((item, indice) => {
// // má prática!
// // item.name = 'aEW';
// // return item.name;
// // se quiser modificar o valor e retornar todo objeto
// // return {
// // ...item,
// // name: 'aEW',
// // };
// return item.name;
// });
const names = result.results.meuMap(
(item, index) => `[${index}]${item.name}`,
);
console.log(names);
// array original não deverá para ser alterado
// console.log(result.results[0].name, result.results[1].name);
})();
================================================
FILE: module-02 - manipulacao de listas/3.filter.js
================================================
const { obterPessoas } = require('./service');
// nosso proprio filter
Array.prototype.meuFilter = function(callback) {
const itensFiltrados = [];
for (let indice = 0; indice <= this.length - 1; indice++) {
const result = callback(this[indice], indice, this);
if (!result) continue;
itensFiltrados.push(this[indice]);
}
return itensFiltrados;
};
(async main => {
const result = await obterPessoas('a');
const results = result.results;
// const familiaLars = results.filter((item, indice, lista) => {
// return item.name.toLowerCase().indexOf(`lars`) !== -1;
// });
const familiaLars = results.meuFilter((item, indice, lista) => {
return item.name.toLowerCase().indexOf(`lars`) !== -1;
});
const names = familiaLars.map(item => item.name);
console.log(names);
})();
================================================
FILE: module-02 - manipulacao de listas/4.reduce.js
================================================
const { obterPessoas } = require('./service');
Array.prototype.meuReduce = function(callback, valorInicial) {
let valorFinal = typeof valorInicial !== undefined ? valorInicial : this[0];
for (let indice = 0; indice < this.length; indice++) {
valorFinal = callback(valorFinal, this[indice], this);
}
return valorFinal;
};
/** */
//verificar o peso de todas as pessoas para informar à nave
(async main => {
const { results } = await obterPessoas('a');
const pesos = results.map(item => parseInt(item.height));
// const total = pesos.reduce(
// (anterior, proximo, listaOriginal) => anterior + proximo,
// 0,
// );
// const total = pesos.meuReduce(
// (anterior, proximo, listaOriginal) => anterior + proximo,
// 0,
// );
const total = [['Erick', 'Wendel'], ['Nerdzão', 'NodeBR']]
.meuReduce((anterior, proximo) => anterior.concat(proximo), [])
.join(',');
console.log('total', total);
})();
================================================
FILE: module-02 - manipulacao de listas/README.md
================================================
# Manipulação de listas
**UPDATE 10/06/2020**
A API do Swapi.co saiu do ar, use a http://swapi.dev/
- Obter informações da API do Starwars
- Obter pessoas pelo nome ([https://swapi.dev/api/people/?search=r2&format=json](https://swapi.dev/api/people/?search=r2&format=json))
## Instalação
- Consumir API via `axios`
- `npm init -y`
- `npm i axios`
- Criar o arquivo `service.js` para fazer a intermediação entre a API e nossa aplicação
## Rodando
- `npm i`
- `node 1.for-forin-forof.js` para visualizar exemplos com `for`, `forIn` e `forOf`
- `node 2.map.js` para visualizar exemplos de `map` e como criar sua própria função `map`
- `node 3.filter.js` para visualizar exemplos de `filter` e como criar sua própria função `filter`
- `node 4.reduce.js` para visualizar exemplos de `reduce` e como criar sua própria função `reduce`
================================================
FILE: module-02 - manipulacao de listas/package.json
================================================
{
"name": "module-02-lists",
"version": "1.0.0",
"description": "- Obter informações da API do Starwars - Obter pessoas pelo nome ([https://swapi.co/api/people/?search=r2&format=json](https://swapi.co/api/people/?search=r2&format=json))",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "erickwendel",
"license": "ISC",
"dependencies": {
"axios": "^0.18.0"
}
}
================================================
FILE: module-02 - manipulacao de listas/service.js
================================================
const axios = require('axios');
const URL = `https://swapi.dev/api/people`;
async function obterPessoas(nome) {
const url = `${URL}/?search=${nome}&format=json`;
const response = await axios.get(url);
return response.data;
}
module.exports = {
obterPessoas,
};
================================================
FILE: module-03 - Introdução a testes automatizados/README.md
================================================
# Modulo 3 - Introdução a desenvolvimento de testes automatizados
## Instalação (do zero)
- `npm i --save-dev mocha`
- `npm i axios`
## Objetivo
- Iniciar instalação e tomar prática de testes em todas aplicações
- Testar se o mapeamento aconteceu com sucesso
- Mock de requisições externas HTTP
## Comentarios
- Usamos o `nock` para Mockar requisições HTTP
- Requisições de terceiros, não podemos validar se está de pé, mas devemos validar caso os resultados venham conforme o esperado
- Com o `nock` qualquer requisição usando aquela `requisição` será `fakeado` e usaremos o valor de uma variavel definida por nós como resposta padrão
- Com ele podemos validar também possiveís erros com a função `replyWithError('DEU RUIM');`
## Rodando
- `npm i`
- `npm t`
================================================
FILE: module-03 - Introdução a testes automatizados/package.json
================================================
{
"name": "module03-tests",
"version": "1.0.0",
"description": "exemplos de cenários de teste",
"main": "index.js",
"dependencies": {
"axios": "^0.18.0",
"nock": "^9.6.1"
},
"devDependencies": {
"mocha": "^5.2.0"
},
"scripts": {
"test": "mocha -w --reporter nyan"
},
"author": "erickwendel",
"license": "ISC"
}
================================================
FILE: module-03 - Introdução a testes automatizados/service.js
================================================
const axios = require('axios');
const URL = `https://swapi.co/api/people`;
async function obterPessoas(nome) {
const url = `${URL}/?search=${nome}&format=json`;
const response = await axios.get(url);
return response.data.results.map(mapearPessoas);
}
function mapearPessoas(item) {
return {
nome: item.name,
peso: item.height,
};
}
module.exports = {
obterPessoas,
};
================================================
FILE: module-03 - Introdução a testes automatizados/test.js
================================================
const { deepEqual } = require('assert');
const { obterPessoas } = require('./service');
// mock de requisiçoes HTTP
const nock = require('nock');
describe('Swar Wars Tests', function() {
this.timeout(3000);
this.beforeEach(() => {
const response = {
count: 1,
next: null,
previous: null,
results: [
{
name: 'R2-D2',
height: '96',
mass: '32',
hair_color: 'n/a',
skin_color: 'white, blue',
eye_color: 'red',
birth_year: '33BBY',
gender: 'n/a',
homeworld: 'https://swapi.co/api/planets/8/',
vehicles: [],
starships: [],
created: '2014-12-10T15:11:50.376000Z',
edited: '2014-12-20T21:17:50.311000Z',
url: 'https://swapi.co/api/people/3/',
},
],
};
// toda vez que bater nessa API vai retornar esse valor
// quando rolar algum resultado diferente o nock vai reclamar
// requisições externas não são problemas nossos! Mas temos que validar caso
// esteja tudo nos conformes, trazer as informações conforme o esperado
nock('https://swapi.co/api/people')
.get(`/?search=r2-d2&format=json`)
.reply(200, response);
});
it('deve buscar r2d2 com o formato correto', async () => {
const expected = [{ nome: 'R2-D2', peso: '96' }];
const nomeBase = `r2-d2`;
const resultado = await obterPessoas(nomeBase);
deepEqual(expected, resultado);
});
it('deve buscar r2d2 com o formato correto', async () => {
const expected = [{ nome: 'R2-D2', peso: '96' }];
const nomeBase = `r2-d2`;
const resultado = await obterPessoas(nomeBase);
deepEqual(expected, resultado);
});
});
================================================
FILE: module-04 - ferramentas de linha de comando/cli.js
================================================
const commander = require('commander');
const Heroi = require('./heroi');
const Database = require('./database');
(async () => {
/**
* node cli.js --help
*/
commander
.version('v1')
.option('-n, --nome [value]', 'adicionar nome')
.option('-p, --poder [value]', 'adicionar poder')
//CRUD
.option('-c, --cadastrar', 'cadastrar Heroi')
.option('-r, --listar [value]', 'listar herois pelo id')
.option('-u, --atualizar [value]', 'atualizar heroi pelo id')
.option('-d, --remover [value]', 'remover heroi pelo id')
.parse(process.argv);
const heroi = new Heroi(commander);
try {
/**
* node cli.js --cadastrar params...
* node cli.js -c -n Hulk -p Forca
*/
if (commander.cadastrar) {
await Database.cadastrar(heroi);
console.log('item cadastrado com sucesso!');
return;
}
/**
* node cli.js --listar
* node cli.js -r
* node cli.js -r 1
*/
if (commander.listar) {
const id = commander.listar;
const result = await Database.listar(id);
console.log(result);
return;
}
/**
* node cli.js --atualizar
* node cli.js -u 1 -n papa
* node cli.js -u 1 -n thor -p trovao
*/
if (commander.atualizar) {
const id = commander.atualizar;
console.log('id', id);
await Database.atualizar(id, heroi);
console.log('item atualizado com sucesso!');
return;
}
/**
* node cli.js --remover
* node cli.js -d 1
*/
if (commander.remover) {
const id = commander.remover;
await Database.remover(id);
console.log('item removido com sucesso!');
return;
}
} catch (error) {
console.error('DEU RUIM', error);
return;
}
})();
================================================
FILE: module-04 - ferramentas de linha de comando/database.js
================================================
/*
*/
const { writeFile, readFile } = require('fs');
const { promisify } = require('util');
const [writeFileAsync, readFileAsync] = [
promisify(writeFile),
promisify(readFile),
];
class Database {
constructor() {
this.FILENAME = 'heroes.json';
}
async obterArquivo() {
const arquivo = await readFileAsync(this.FILENAME);
return JSON.parse(arquivo.toString());
}
async escreverArquivo(dados) {
await writeFileAsync(this.FILENAME, JSON.stringify(dados));
return true;
}
async cadastrar(heroi) {
const dados = await this.obterArquivo();
//workaround para simular um id
const id = heroi.id <= 2 ? heroi.id : Date.now();
const heroiComId = {
...heroi,
id,
};
return await this.escreverArquivo([...dados, heroiComId]);
}
async listar(id) {
const dados = await this.obterArquivo();
// se nao passar o id, traz tudo
return dados.filter(item => (id ? item.id == id : true));
}
async atualizar(id, atualizacoes) {
const dados = await this.obterArquivo();
const indice = dados.findIndex(item => item.id === parseInt(id));
if (indice === -1) {
throw Error('heroi não existe!');
}
const atual = dados[indice];
dados.splice(indice, 1);
//workaround para remover valores undefined do objeto
const objAtualizado = JSON.parse(JSON.stringify(atualizacoes));
const dadoAtualizado = Object.assign({}, atual, objAtualizado);
return await this.escreverArquivo([...dados, dadoAtualizado]);
}
async remover(id) {
if (!id) {
await this.escreverArquivo([]);
return true;
}
const dados = await this.obterArquivo();
const indice = dados.findIndex(item => item.id === parseInt(id));
if (indice === -1) {
throw Error('heroi não existe!');
}
const atual = dados[indice];
dados.splice(indice, 1);
await this.escreverArquivo(dados);
return true;
}
}
module.exports = new Database();
================================================
FILE: module-04 - ferramentas de linha de comando/heroes.json
================================================
[{"nome":"Flash","poder":"speed","id":1},{"nome":"Flash","poder":"speed","id":1},{"nome":"Batman","poder":"ricão","id":2}]
================================================
FILE: module-04 - ferramentas de linha de comando/heroi.js
================================================
class Heroi {
constructor({ id, nome, poder }) {
this.nome = nome;
this.poder = poder;
this.id = id || Date.now();
}
}
module.exports = Heroi;
================================================
FILE: module-04 - ferramentas de linha de comando/package.json
================================================
{
"name": "module04-arquivos",
"version": "1.0.0",
"description": "",
"main": "database.js",
"scripts": {
"test": "mocha -w --reporter nyan"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"commander": "^2.18.0"
}
}
================================================
FILE: module-04 - ferramentas de linha de comando/test.js
================================================
const { deepEqual, ok } = require('assert');
const Database = require('./database');
const DEFAULT_ITEM_CADASTRAR = { nome: 'Flash', poder: 'speed', id: 1 };
const DEFAULT_ITEM_ATUALIZAR = {
nome: 'Lanterna Verde',
poder: 'Anel do poder',
id: 2,
};
describe('Suite de manipulação de herois', () => {
before(async () => {
await Database.remover();
await Database.cadastrar(DEFAULT_ITEM_CADASTRAR);
await Database.cadastrar(DEFAULT_ITEM_ATUALIZAR);
});
it('deve cadastrar um heroi', async () => {
const expected = DEFAULT_ITEM_CADASTRAR;
await Database.cadastrar(DEFAULT_ITEM_CADASTRAR);
const [realResult] = await Database.listar(expected.id);
deepEqual(realResult, expected);
});
it('deve listar um heroi pelo id', async () => {
const expected = DEFAULT_ITEM_CADASTRAR;
const result = await Database.listar(1);
deepEqual(result[0], expected);
});
it('deve atualizar um heroi pelo id', async () => {
const expected = {
...DEFAULT_ITEM_ATUALIZAR,
nome: 'Batman',
poder: 'ricão',
};
await Database.atualizar(expected.id, {
nome: expected.nome,
poder: expected.poder,
});
const [realResult] = await Database.listar(expected.id);
deepEqual(realResult, expected);
});
});
================================================
FILE: module-05 - nosso projeto multi-database/README.md
================================================
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
================================================
FILE: module-05 - nosso projeto multi-database/index.js
================================================
const mongoS = require('./src/db/strategies/mongoDbStrategy')
const postgS = require('./src/db/strategies/postgresStrategy')
const Context = require('./src/db/strategies/base/contextStrategy');
const contextM = new Context( new mongoS())
console.log(contextM.create())
const contextP = new Context( new postgS())
console.log(contextP.create())
================================================
FILE: module-05 - nosso projeto multi-database/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w *.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {}
}
================================================
FILE: module-05 - nosso projeto multi-database/scripts/mongodb.sh
================================================
use herois-db
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-05 - nosso projeto multi-database/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-05 - nosso projeto multi-database/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-05 - nosso projeto multi-database/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-05 - nosso projeto multi-database/src/db/strategies/mongoDbStrategy.js
================================================
const IDb = require('./base/interfaceDb');
class MongoDBStrategy extends IDb {
constructor() {
super();
}
create(item) {
return 'MongoDB';
}
}
module.exports = MongoDBStrategy;
================================================
FILE: module-05 - nosso projeto multi-database/src/db/strategies/postgresStrategy.js
================================================
const IDb = require('./base/interfaceDb');
class PostgresStrategy extends IDb {
constructor() {
super();
}
create(item) {
return 'Postgres';
}
}
module.exports = PostgresStrategy;
================================================
FILE: module-05 - nosso projeto multi-database/src/example1.js
================================================
basclass NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-06 - postgres e modelos relacionais/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_DB=herois \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
docker run -it \
-p 5432:5432 \
--link postgres:postgres \
postgres psql -h $HOST -p $PORT -U $USER $DATABASE
```
- Go to `http://localhost:8080/?pgsql=postgres&username=postgres&db=heroes&ns=public`
================================================
FILE: module-06 - postgres e modelos relacionais/index.js
================================================
================================================
FILE: module-06 - postgres e modelos relacionais/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w *.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-06 - postgres e modelos relacionais/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-06 - postgres e modelos relacionais/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('./src/db/strategies/postgresSQLStrategy');
const Context = require('./src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
const context = new Context(new PostgresStrategy());
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-06 - postgres e modelos relacionais/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-06 - postgres e modelos relacionais/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-06 - postgres e modelos relacionais/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-06 - postgres e modelos relacionais/src/db/strategies/mongoDbStrategy.js
================================================
const IDb = require('./base/interfaceDb');
class MongoDBStrategy extends IDb {
constructor() {
super();
}
create(item) {
return 'MongoDB';
}
}
module.exports = MongoDBStrategy;
================================================
FILE: module-06 - postgres e modelos relacionais/src/db/strategies/postgresSQLStrategy.js
================================================
const IDb = require('./base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLConnection {
static connect() {}
}
class PostgreSQLStrategy extends IDb {
constructor() {
super();
this._herois = null;
this._sequelize = null;
this._connect();
}
defineModel() {
this._herois = this._sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
}
_connect() {
this._sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
},
);
this.defineModel();
}
async isConnected() {
try {
// await this._connect();
await this._sequelize.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._herois.create(item, { raw: true });
}
read(item) {
return this._herois.findAll({ where: item, raw: true });
}
update(id, item) {
return this._herois.update(item, { where: { id } });
}
delete(id) {
const query = id ? { id } : {};
return this._herois.destroy({ where: query });
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-06 - postgres e modelos relacionais/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
// context.read();
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/index.js
================================================
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/server.js
================================================
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/src/db/strategies/mongoDbStrategy.js
================================================
const ICrud = require('./base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
constructor() {
super()
this._herois = null
this._driver = null
}
async isConnected() {
const state = STATUS[this._driver.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._driver.readyState]
}
defineModel() {
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
this._herois = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
}
connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
this._driver = Mongoose.connection
this._driver.once('open', () => console.log('database rodando!!'))
this.defineModel()
}
async create(item) {
return this._herois.create(item)
}
async read(item = {}) {
return this._herois.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._herois.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._herois.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/src/db/strategies/postgresSQLStrategy.js
================================================
const IDb = require('./base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLConnection {
static connect() {}
}
class PostgreSQLStrategy extends IDb {
constructor() {
super();
this._herois = null;
this._sequelize = null;
}
async defineModel() {
this._herois = this._sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
await this._herois.sync()
}
async connect() {
this._sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
await this.defineModel();
}
async isConnected() {
try {
// await this._connect();
await this._sequelize.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._herois.create(item, { raw: true });
}
read(item) {
return this._herois.findAll({ where: item, raw: true });
}
update(id, item) {
return this._herois.update(item, { where: { id } });
}
delete(id) {
const query = id ? { id } : {};
return this._herois.destroy({ where: query });
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('./../src/db/strategies/mongoDbStrategy')
const Context = require('./../src/db/strategies/base/contextStrategy')
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
const context = new Context(new MongoDb())
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
await context.connect()
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-07 - mongodb e bancos nao-relacionais/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgresSQLStrategy');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
const context = new Context(new PostgresStrategy());
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
await context.connect()
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.0 - organização de bases/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.0 - organização de bases/index.js
================================================
================================================
FILE: module-08.0 - organização de bases/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.0 - organização de bases/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.0 - organização de bases/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.0 - organização de bases/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.0 - organização de bases/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.0 - organização de bases/server.js
================================================
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 1o
constructor(connection, schema) {
super()
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 3o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
//1o
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
//2o
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.0 - organização de bases/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.0 - organização de bases/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.0 - organização de bases/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('./../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('./../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.0 - organização de bases/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
// 1o criar pasta postgres
// 2o criar schema heroiSchema
// 3o alterar classe postgres
// constructor
// defineModel
// isConnected
// connection
// alterar _herois para _schema
// 4o alterar teste
//adicionar connect
// adicionar defineModel
// adicionar context
// testar
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.1 - hapi - estrutura e listar/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.1 - hapi - estrutura e listar/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.1 - hapi - estrutura e listar/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const app = new Hapi.Server({
port: 4000
})
function mapRoutes (instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.1 - hapi - estrutura e listar/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.1 - hapi - estrutura e listar/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.1 - hapi - estrutura e listar/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.1 - hapi - estrutura e listar/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.1 - hapi - estrutura e listar/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.1 - hapi - estrutura e listar/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.1 - hapi - estrutura e listar/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return this.db.read()
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.1 - hapi - estrutura e listar/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
describe.only('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
})
================================================
FILE: module-08.1 - hapi - estrutura e listar/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.1 - hapi - estrutura e listar/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.2 - hapi - cadastrar/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.2 - hapi - cadastrar/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.2 - hapi - cadastrar/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.2 - hapi - cadastrar/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.2 - hapi - cadastrar/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha -w tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.2 - hapi - cadastrar/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.2 - hapi - cadastrar/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.2 - hapi - cadastrar/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.2 - hapi - cadastrar/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.2 - hapi - cadastrar/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.2 - hapi - cadastrar/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.2 - hapi - cadastrar/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.2 - hapi - cadastrar/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.2 - hapi - cadastrar/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
describe.only('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
})
================================================
FILE: module-08.2 - hapi - cadastrar/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('./../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('./../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.2 - hapi - cadastrar/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.3 - hapi - joi/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.3 - hapi - joi/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.3 - hapi - joi/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.3 - hapi - joi/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.3 - hapi - joi/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"joi": "^14.1.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.3 - hapi - joi/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.3 - hapi - joi/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.3 - hapi - joi/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.3 - hapi - joi/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.3 - hapi - joi/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.3 - hapi - joi/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.3 - hapi - joi/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.3 - hapi - joi/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.3 - hapi - joi/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
})
================================================
FILE: module-08.3 - hapi - joi/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.3 - hapi - joi/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.4 - hapi - atualizar/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.4 - hapi - atualizar/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.4 - hapi - atualizar/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.4 - hapi - atualizar/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.4 - hapi - atualizar/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"joi": "^14.1.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.4 - hapi - atualizar/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.4 - hapi - atualizar/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.4 - hapi - atualizar/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.4 - hapi - atualizar/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.4 - hapi - atualizar/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.4 - hapi - atualizar/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.4 - hapi - atualizar/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.4 - hapi - atualizar/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
},
params: {
id: Joi.string().required()
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.4 - hapi - atualizar/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe.only('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
})
================================================
FILE: module-08.4 - hapi - atualizar/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.4 - hapi - atualizar/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.5 - hapi - remover/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.5 - hapi - remover/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.5 - hapi - remover/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.5 - hapi - remover/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.5 - hapi - remover/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"joi": "^14.1.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0"
}
}
================================================
FILE: module-08.5 - hapi - remover/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.5 - hapi - remover/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.5 - hapi - remover/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.5 - hapi - remover/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.5 - hapi - remover/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.5 - hapi - remover/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.5 - hapi - remover/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.5 - hapi - remover/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
},
params: {
id: Joi.string().required()
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
validate: {
failAction: (request, h, err) => {
throw err;
},
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.5 - hapi - remover/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-08.5 - hapi - remover/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.5 - hapi - remover/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.6 - hapi - swagger/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.6 - hapi - swagger/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.6 - hapi - swagger/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.6 - hapi - swagger/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.6 - hapi - swagger/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"hapi": "^17.7.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-08.6 - hapi - swagger/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.6 - hapi - swagger/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.6 - hapi - swagger/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.6 - hapi - swagger/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.6 - hapi - swagger/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.6 - hapi - swagger/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.6 - hapi - swagger/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.6 - hapi - swagger/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois'
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.6 - hapi - swagger/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-08.6 - hapi - swagger/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.6 - hapi - swagger/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.7 - hapi - jwt/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.7 - hapi - jwt/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.7 - hapi - jwt/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const AuthRoutes = require('./src/routes/authRoutes')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const Jwt = require('jsonwebtoken')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = 'ESSA_E_TRETA'
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.7 - hapi - jwt/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.7 - hapi - jwt/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"boom": "^7.2.2",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-08.7 - hapi - jwt/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.7 - hapi - jwt/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.7 - hapi - jwt/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.7 - hapi - jwt/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.7 - hapi - jwt/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.7 - hapi - jwt/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.7 - hapi - jwt/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key) {
super()
this.secret = key
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: (request, headers) => {
const {
username,
password
} = request.payload
if (
username.toLowerCase() !== USER.username ||
password !== USER.password
)
return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-08.7 - hapi - jwt/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.7 - hapi - jwt/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.7 - hapi - jwt/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois'
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-08.7 - hapi - jwt/tests/auth.test.js
================================================
const assert = require('assert')
const api = require('../api')
let app = {}
describe.only('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'Xuxadasilva',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-08.7 - hapi - jwt/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.7 - hapi - jwt/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.8 - hapi - jwt-herois/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.8 - hapi - jwt-herois/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.8 - hapi - jwt-herois/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const AuthRoutes = require('./src/routes/authRoutes')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const HeroRoutes = require('./src/routes/heroRoutes')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const Jwt = require('jsonwebtoken')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = 'ESSA_E_TRETA'
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.8 - hapi - jwt-herois/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.8 - hapi - jwt-herois/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"boom": "^7.2.2",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-08.8 - hapi - jwt-herois/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.8 - hapi - jwt-herois/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.8 - hapi - jwt-herois/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.8 - hapi - jwt-herois/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item) {
return this._db.update(item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.8 - hapi - jwt-herois/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.8 - hapi - jwt-herois/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.8 - hapi - jwt-herois/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key) {
super()
this.secret = key
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: (request, headers) => {
const {
username,
password
} = request.payload
if (
username.toLowerCase() !== USER.username ||
password !== USER.password
)
return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-08.8 - hapi - jwt-herois/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.8 - hapi - jwt-herois/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
headers: Joi.object({
authorization: Joi.string().required()
}).unknown()
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.8 - hapi - jwt-herois/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
let MOCK_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh1eGFkYXNpbHZhIiwiaWF0IjoxNTQyNzI4MzQ0fQ.JvBOZa7yXds4ktQ7HvNRYO6-s1mbU7AKTJP9G2ghje4"
const headers = {
Authorization: MOCK_TOKEN
}
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('não deve listar herois sem um token', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
headers
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
headers,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`,
headers,
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-08.8 - hapi - jwt-herois/tests/auth.test.js
================================================
const assert = require('assert')
const api = require('../api')
let app = {}
describe('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'Xuxadasilva',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-08.8 - hapi - jwt-herois/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.8 - hapi - jwt-herois/tests/postgresStrategy.test.js
================================================
const { equal, deepEqual, ok } = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = { nome: 'Gaviao Negro', poder: 'flexas' };
const MOCK_HEROI_ATUALIZAR = { nome: 'Mulher Gavião', poder: 'grito' };
let context = {}
describe('PostgreSQL Strategy', function() {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-08.9 - hapi - user-validation/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-08.9 - hapi - user-validation/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-08.9 - hapi - user-validation/api.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroRoutes = require('./src/routes/heroRoutes')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const PostgresDB = require('./src/db/strategies/postgres/postgresSQLStrategy')
const AuthRoutes = require('./src/routes/authRoutes')
const UserSchema = require('./src/db/strategies/postgres/schemas/userSchema')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const Jwt = require('jsonwebtoken')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = 'ESSA_E_TRETA'
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: 4000
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA, postgresModel), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-08.9 - hapi - user-validation/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-08.9 - hapi - user-validation/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"bcrypt": "^3.0.2",
"boom": "^7.2.2",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-08.9 - hapi - user-validation/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-08.9 - hapi - user-validation/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-08.9 - hapi - user-validation/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_USUARIOS;
CREATE TABLE TB_USUARIOS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL
);
-- create
INSERT INTO TB_USUARIOS
(USERNAME, PASSWORD)
VALUES
('xuxadasilva', '$2b$10$8I99eSf.DcubdihXUXO6weT9iriDG0UIm13d5Ji1TCB1kq88LwZdy');
---
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-08.9 - hapi - user-validation/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item, upsert) {
return this._database.update(id, item, upsert);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect('mongodb://erickwendel:minhasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, { nome: 1, poder: 1, insertedAt: 1})
}
async update(id, item) {
return this._collection.updateOne({_id: id}, { $set: item})
}
async delete(id) {
return this._collection.deleteOne({_id: id})
}
}
module.exports = MongoDB
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(
'heroes', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
// dialectOptions: {
// ssl: true,
},
);
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item, upsert = false) {
const fn = upsert ? 'upsert' : 'update'
return this._db[fn](item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
name: 'herois',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-08.9 - hapi - user-validation/src/db/strategies/postgres/schemas/userSchema.js
================================================
const Sequelize = require('sequelize')
const UserSchema = {
name: 'users',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
unique: true,
required: true,
},
password: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_USUARIOS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = UserSchema
================================================
FILE: module-08.9 - hapi - user-validation/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-08.9 - hapi - user-validation/src/helpers/passwordHelper.js
================================================
const Bcrypt = require('bcrypt')
const {
promisify
} = require('util')
const hashAsync = promisify(Bcrypt.hash)
const compareAsync = promisify(Bcrypt.compare)
const SALT = 3
class Password {
static hashPassword(pass) {
return hashAsync(pass, SALT)
}
static comparePassword(pass, hash) {
return compareAsync(pass, hash)
}
}
module.exports = Password
================================================
FILE: module-08.9 - hapi - user-validation/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const PasswordHelper = require('./../helpers/passwordHelper')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key, db) {
super()
this.secret = key
this.db = db
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: async (request, headers) => {
const {
username,
password
} = request.payload
const [user] = await this.db.read({
username: username.toLowerCase()
})
if (!user) {
return Boom.unauthorized('O usuario informado nao existe')
}
const match = await PasswordHelper.comparePassword(password, user.password)
if (!match) {
return Boom.unauthorized('O usuario e senha invalidos!')
}
// if (
// username.toLowerCase() !== USER.username ||
// password !== USER.password
// )
// return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-08.9 - hapi - user-validation/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-08.9 - hapi - user-validation/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
headers: Joi.object({
authorization: Joi.string().required()
}).unknown()
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-08.9 - hapi - user-validation/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
let MOCK_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh1eGFkYXNpbHZhIiwiaWF0IjoxNTQyNzI4MzQ0fQ.JvBOZa7yXds4ktQ7HvNRYO6-s1mbU7AKTJP9G2ghje4"
const headers = {
Authorization: MOCK_TOKEN
}
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('não deve listar herois sem um token', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
headers
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
headers,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`,
headers,
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-08.9 - hapi - user-validation/tests/auth.test.js
================================================
//1o criar test
//2o criar passwordHelper
//3o gerar senha e guardar
//4o criar model de usuario
//5o adicionar chamada em api.js
//6o adicionar no construtor de auth receber o model
//7o criar logica na route
//8o adicionar upsert no context e postgresStrategy
//9o adicionar no arquivo postgres.sql o script para criar a tabela
const assert = require('assert')
const api = require('../api')
const Context = require('./../src/db/strategies/base/contextStrategy')
const PostgresDB = require('./../src/db/strategies/postgres/postgresSQLStrategy')
const UserSchema = require('./../src/db/strategies/postgres/schemas/userSchema')
let app = {}
const USER = {
username: 'xuxadasilva',
password: '321123'
}
const USER_DB = {
...USER,
password: '$2b$04$SdlyEJsy.o5UgsgVr5csJ.ralZVyPviGH80BOb0zJCTSis30RB8Ba'
}
describe('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
await postgresModel.update(null, USER_DB, true)
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: USER
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-08.9 - hapi - user-validation/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-08.9 - hapi - user-validation/tests/passwordHelper.test.js
================================================
const assert = require('assert');
const PasswordHelper = require('../src/helpers/passwordHelper');
const SENHA = 'erick@32123';
const HASH = '$2b$04$nJuOS9YZH9FpsKTOSh2IPOZUW9IF83bo54FE2L/rO/Xzrl.pS/qV2'
describe('UserHelper test suite', function () {
it('deve gerar um hash a partir de uma senha', async () => {
const result = await PasswordHelper.hashPassword(SENHA);
// const result = await PasswordHelper.hashPassword('321123');
// console.log('result', result)
assert.ok(result.length > 10);
});
it('deve comparar uma senha e seu hash', async () => {
const result = PasswordHelper.comparePassword(SENHA, HASH)
assert.ok(result)
})
});
================================================
FILE: module-08.9 - hapi - user-validation/tests/postgresStrategy.test.js
================================================
const {
equal,
deepEqual,
ok
} = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Gavião',
poder: 'grito'
};
let context = {}
describe('PostgreSQL Strategy', function () {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-09 - enviroment/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
sleep 3;
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-09 - enviroment/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-09 - enviroment/api.js
================================================
/**
* 1o create config files
* 2o find variables
* 3o alter postgres to URI
* 4o install dotenv
* 5o replace variables
*/
const {
join
} = require('path')
const {
config
} = require('dotenv')
const {
ok
} = require('assert')
const env = process.env.NODE_ENV || "dev"
ok(env === "prod" || env === "dev", "environment inválida! Ou prod ou dev")
const configPath = join('./config', `.env.${env}`)
config({
path: configPath
})
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroRoutes = require('./src/routes/heroRoutes')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const PostgresDB = require('./src/db/strategies/postgres/postgresSQLStrategy')
const AuthRoutes = require('./src/routes/authRoutes')
const UserSchema = require('./src/db/strategies/postgres/schemas/userSchema')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = process.env.JWT_KEY
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: process.env.PORT
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA, postgresModel), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-09 - enviroment/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-09 - enviroment/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "mocha tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"bcrypt": "^3.0.2",
"boom": "^7.2.2",
"dotenv": "^6.2.0",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-09 - enviroment/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-09 - enviroment/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-09 - enviroment/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_USUARIOS;
CREATE TABLE TB_USUARIOS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL
);
-- create
INSERT INTO TB_USUARIOS
(USERNAME, PASSWORD)
VALUES
('xuxadasilva', '$2b$10$8I99eSf.DcubdihXUXO6weT9iriDG0UIm13d5Ji1TCB1kq88LwZdy');
---
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-09 - enviroment/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-09 - enviroment/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item, upsert) {
return this._database.update(id, item, upsert);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-09 - enviroment/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-09 - enviroment/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect(process.env.MONGO_URL, {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, {
nome: 1,
poder: 1,
insertedAt: 1
})
}
async update(id, item) {
return this._collection.updateOne({
_id: id
}, {
$set: item
})
}
async delete(id) {
return this._collection.deleteOne({
_id: id
})
}
}
module.exports = MongoDB
================================================
FILE: module-09 - enviroment/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-09 - enviroment/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(process.env.POSTGRES_URL, {
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
})
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item, upsert = false) {
const fn = upsert ? 'upsert' : 'update'
return this._db[fn](item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-09 - enviroment/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
name: 'herois',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-09 - enviroment/src/db/strategies/postgres/schemas/userSchema.js
================================================
const Sequelize = require('sequelize')
const UserSchema = {
name: 'users',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
unique: true,
required: true,
},
password: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_USUARIOS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = UserSchema
================================================
FILE: module-09 - enviroment/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-09 - enviroment/src/helpers/passwordHelper.js
================================================
const Bcrypt = require('bcrypt')
const {
promisify
} = require('util')
const hashAsync = promisify(Bcrypt.hash)
const compareAsync = promisify(Bcrypt.compare)
const SALT = parseInt(process.env.PWD_SALT)
class Password {
static hashPassword(pass) {
return hashAsync(pass, SALT)
}
static comparePassword(pass, hash) {
return compareAsync(pass, hash)
}
}
module.exports = Password
================================================
FILE: module-09 - enviroment/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const PasswordHelper = require('./../helpers/passwordHelper')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key, db) {
super()
this.secret = key
this.db = db
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: async (request, headers) => {
const {
username,
password
} = request.payload
const [user] = await this.db.read({
username: username.toLowerCase()
})
if (!user) {
return Boom.unauthorized('O usuario informado nao existe')
}
const match = await PasswordHelper.comparePassword(password, user.password)
if (!match) {
return Boom.unauthorized('O usuario e senha invalidos!')
}
// if (
// username.toLowerCase() !== USER.username ||
// password !== USER.password
// )
// return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-09 - enviroment/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-09 - enviroment/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
headers: Joi.object({
authorization: Joi.string().required()
}).unknown()
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-09 - enviroment/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
let MOCK_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh1eGFkYXNpbHZhIiwiaWF0IjoxNTQyNzI4MzQ0fQ.JvBOZa7yXds4ktQ7HvNRYO6-s1mbU7AKTJP9G2ghje4"
const headers = {
Authorization: MOCK_TOKEN
}
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('não deve listar herois sem um token', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
headers
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
headers,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`,
headers,
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-09 - enviroment/tests/auth.test.js
================================================
//1o criar test
//2o criar passwordHelper
//3o gerar senha e guardar
//4o criar model de usuario
//5o adicionar chamada em api.js
//6o adicionar no construtor de auth receber o model
//7o criar logica na route
//8o adicionar upsert no context e postgresStrategy
//9o adicionar no arquivo postgres.sql o script para criar a tabela
const assert = require('assert')
const api = require('../api')
const Context = require('./../src/db/strategies/base/contextStrategy')
const PostgresDB = require('./../src/db/strategies/postgres/postgresSQLStrategy')
const UserSchema = require('./../src/db/strategies/postgres/schemas/userSchema')
let app = {}
const USER = {
username: 'xuxadasilva',
password: '321123'
}
const USER_DB = {
...USER,
password: '$2b$04$SdlyEJsy.o5UgsgVr5csJ.ralZVyPviGH80BOb0zJCTSis30RB8Ba'
}
describe('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
await postgresModel.update(null, USER_DB, true)
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: USER
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-09 - enviroment/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const { nome, poder } = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({ nome, poder }, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{ nome, poder}] = await context.read({ nome: MOCK_HEROI_CADASTRAR.nome})
const result = {
nome, poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-09 - enviroment/tests/passwordHelper.test.js
================================================
const assert = require('assert');
const PasswordHelper = require('../src/helpers/passwordHelper');
const SENHA = 'erick@32123';
const HASH = '$2b$04$nJuOS9YZH9FpsKTOSh2IPOZUW9IF83bo54FE2L/rO/Xzrl.pS/qV2'
describe('UserHelper test suite', function () {
it('deve gerar um hash a partir de uma senha', async () => {
const result = await PasswordHelper.hashPassword(SENHA);
// const result = await PasswordHelper.hashPassword('321123');
// console.log('result', result)
assert.ok(result.length > 10);
});
it('deve comparar uma senha e seu hash', async () => {
const result = PasswordHelper.comparePassword(SENHA, HASH)
assert.ok(result)
})
});
================================================
FILE: module-09 - enviroment/tests/postgresStrategy.test.js
================================================
const {
equal,
deepEqual,
ok
} = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Gavião',
poder: 'grito'
};
let context = {}
describe('PostgreSQL Strategy', function () {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-10 - production-mongodb-postgres/.gitignore
================================================
node_modules
================================================
FILE: module-10 - production-mongodb-postgres/Procfile
================================================
web: npm run prod
================================================
FILE: module-10 - production-mongodb-postgres/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
sleep 5;
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-10 - production-mongodb-postgres/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-10 - production-mongodb-postgres/api.js
================================================
/**
* 1o Add procfile
* 2o up to heroku
*
*
* 2o add mlab
* 3o run NODE_ENV=prod npm t
*
* 4o add postgres
* 5o add process.env.SSL_DB
* 6o add sequelize ssl
* 7o modify npm t --timeout 10000
* 8o upto heroku
*
* 9o install pm2
* 10 up to heroku
* 11 add pm2 to pre-install
* 12 up to heroku
*/
const {
join
} = require('path')
const {
config
} = require('dotenv')
const {
ok
} = require('assert')
const env = process.env.NODE_ENV || "dev"
ok(env === "prod" || env === "dev", "environment inválida! Ou prod ou dev")
const configPath = join('./config', `.env.${env}`)
config({
path: configPath
})
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroRoutes = require('./src/routes/heroRoutes')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const PostgresDB = require('./src/db/strategies/postgres/postgresSQLStrategy')
const AuthRoutes = require('./src/routes/authRoutes')
const UserSchema = require('./src/db/strategies/postgres/schemas/userSchema')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = process.env.JWT_KEY
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: process.env.PORT
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA, postgresModel), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-10 - production-mongodb-postgres/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-10 - production-mongodb-postgres/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"preinstall": "npm i -g pm2",
"prod": "cross-env NODE_ENV=prod pm2-runtime api.js",
"start": "nodemon api.js",
"test": "mocha --timeout 10000 tests/*.test.js"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0"
},
"dependencies": {
"bcrypt": "^3.0.2",
"boom": "^7.2.2",
"cross-env": "^5.2.0",
"dotenv": "^6.2.0",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-10 - production-mongodb-postgres/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-10 - production-mongodb-postgres/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-10 - production-mongodb-postgres/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_USUARIOS;
CREATE TABLE TB_USUARIOS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL
);
-- create
INSERT INTO TB_USUARIOS
(USERNAME, PASSWORD)
VALUES
('xuxadasilva', '$2b$10$8I99eSf.DcubdihXUXO6weT9iriDG0UIm13d5Ji1TCB1kq88LwZdy');
---
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-10 - production-mongodb-postgres/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item, upsert) {
return this._database.update(id, item, upsert);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect(process.env.MONGO_URL, {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, {
nome: 1,
poder: 1,
insertedAt: 1
})
}
async update(id, item) {
return this._collection.updateOne({
_id: id
}, {
$set: item
})
}
async delete(id) {
return this._collection.deleteOne({
_id: id
})
}
}
module.exports = MongoDB
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(process.env.POSTGRES_URL, {
quoteIdentifiers: false,
ssl: process.env.SSL_DB,
dialectOptions: {
ssl: process.env.SSL_DB,
},
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
})
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item, upsert = false) {
const fn = upsert ? 'upsert' : 'update'
return this._db[fn](item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
name: 'herois',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-10 - production-mongodb-postgres/src/db/strategies/postgres/schemas/userSchema.js
================================================
const Sequelize = require('sequelize')
const UserSchema = {
name: 'users',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
unique: true,
required: true,
},
password: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_USUARIOS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = UserSchema
================================================
FILE: module-10 - production-mongodb-postgres/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-10 - production-mongodb-postgres/src/helpers/passwordHelper.js
================================================
const Bcrypt = require('bcrypt')
const {
promisify
} = require('util')
const hashAsync = promisify(Bcrypt.hash)
const compareAsync = promisify(Bcrypt.compare)
const SALT = parseInt(process.env.PWD_SALT)
class Password {
static hashPassword(pass) {
return hashAsync(pass, SALT)
}
static comparePassword(pass, hash) {
return compareAsync(pass, hash)
}
}
module.exports = Password
================================================
FILE: module-10 - production-mongodb-postgres/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const PasswordHelper = require('./../helpers/passwordHelper')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key, db) {
super()
this.secret = key
this.db = db
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: async (request, headers) => {
const {
username,
password
} = request.payload
const [user] = await this.db.read({
username: username.toLowerCase()
})
if (!user) {
return Boom.unauthorized('O usuario informado nao existe')
}
const match = await PasswordHelper.comparePassword(password, user.password)
if (!match) {
return Boom.unauthorized('O usuario e senha invalidos!')
}
// if (
// username.toLowerCase() !== USER.username ||
// password !== USER.password
// )
// return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-10 - production-mongodb-postgres/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-10 - production-mongodb-postgres/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
headers: Joi.object({
authorization: Joi.string().required()
}).unknown()
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-10 - production-mongodb-postgres/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
let MOCK_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh1eGFkYXNpbHZhIiwiaWF0IjoxNTQyNzI4MzQ0fQ.JvBOZa7yXds4ktQ7HvNRYO6-s1mbU7AKTJP9G2ghje4"
const headers = {
Authorization: MOCK_TOKEN
}
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('não deve listar herois sem um token', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
headers
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
headers,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`,
headers,
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-10 - production-mongodb-postgres/tests/auth.test.js
================================================
//1o criar test
//2o criar passwordHelper
//3o gerar senha e guardar
//4o criar model de usuario
//5o adicionar chamada em api.js
//6o adicionar no construtor de auth receber o model
//7o criar logica na route
//8o adicionar upsert no context e postgresStrategy
//9o adicionar no arquivo postgres.sql o script para criar a tabela
const assert = require('assert')
const api = require('../api')
const Context = require('./../src/db/strategies/base/contextStrategy')
const PostgresDB = require('./../src/db/strategies/postgres/postgresSQLStrategy')
const UserSchema = require('./../src/db/strategies/postgres/schemas/userSchema')
let app = {}
const USER = {
username: 'xuxadasilva',
password: '321123'
}
const USER_DB = {
...USER,
password: '$2b$04$SdlyEJsy.o5UgsgVr5csJ.ralZVyPviGH80BOb0zJCTSis30RB8Ba'
}
describe('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
await postgresModel.update(null, USER_DB, true)
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: USER
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-10 - production-mongodb-postgres/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const {
nome,
poder
} = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({
nome,
poder
}, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{
nome,
poder
}] = await context.read({
nome: MOCK_HEROI_CADASTRAR.nome
})
const result = {
nome,
poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-10 - production-mongodb-postgres/tests/passwordHelper.test.js
================================================
const assert = require('assert');
const PasswordHelper = require('../src/helpers/passwordHelper');
const SENHA = 'erick@32123';
const HASH = '$2b$04$nJuOS9YZH9FpsKTOSh2IPOZUW9IF83bo54FE2L/rO/Xzrl.pS/qV2'
describe('UserHelper test suite', function () {
it('deve gerar um hash a partir de uma senha', async () => {
const result = await PasswordHelper.hashPassword(SENHA);
// const result = await PasswordHelper.hashPassword('321123');
// console.log('result', result)
assert.ok(result.length > 10);
});
it('deve comparar uma senha e seu hash', async () => {
const result = PasswordHelper.comparePassword(SENHA, HASH)
assert.ok(result)
})
});
================================================
FILE: module-10 - production-mongodb-postgres/tests/postgresStrategy.test.js
================================================
const {
equal,
deepEqual,
ok
} = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Gavião',
poder: 'grito'
};
let context = {}
describe('PostgreSQL Strategy', function () {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});
================================================
FILE: module-11 - istanbul/.gitignore
================================================
node_modules
.nyc_output
coverage
html-test
================================================
FILE: module-11 - istanbul/Procfile
================================================
web: npm run prod
================================================
FILE: module-11 - istanbul/README.md
================================================
# Módulo 5 - Bancos de Dados - Nosso projeto Multi-banco de dados
- Trabalhando com o padrão Strategy para Multi DataSources
## Instalando docker para usar o MongoDB e Postgres
```shell
docker run \
--name postgres \
-e POSTGRES_USER=erickwendel \
-e POSTGRES_PASSWORD=minhasenhasecreta \
-e POSTGRES_DB=heroes \
-p 5432:5432 \
-d \
postgres
docker run \
--name adminer \
-p 8080:8080 \
--link postgres:postgres \
-d \
adminer
## ---- MONGODB
docker run \
--name mongodb \
-p 27017:27017 \
-e MONGO_INITDB_ROOT_USERNAME=admin \
-e MONGO_INITDB_ROOT_PASSWORD=senhaadmin \
-d \
mongo:4
docker run \
--name mongoclient \
-p 3000:3000 \
--link mongodb:mongodb \
-d \
mongoclient/mongoclient
sleep 5;
docker exec -it mongodb \
mongo --host localhost -u admin -p senhaadmin --authenticationDatabase admin \
--eval "db.getSiblingDB('herois').createUser({user: 'erickwendel', pwd: 'minhasenhasecreta', roles: [{role: 'readWrite', db: 'herois'}]})"
```
================================================
FILE: module-11 - istanbul/api-example.js
================================================
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongoDbStrategy')
const mongoDb = new Context(new MongoDB())
const app = new Hapi.Server({
port: 4000
})
async function main() {
mongoDb.connect()
app.route({
path: '/herois',
method: 'GET',
handler: (request, headers) => {
return mongoDb.read()
}
})
await app.start()
console.log('server running at', app.info.port)
}
main()
================================================
FILE: module-11 - istanbul/api.js
================================================
/**
* 1o Add procfile
* 2o up to heroku
* 2o add mlab
* 3o run NODE_ENV=prod npm t
* 4o add postgres
* 5o add process.env.SSL_DB
* 6o add sequelize ssl
* 7o modify npm t --timeout 10000
* 8o upto heroku
* 9o install pm2
* 10 up to heroku
* 11 add pm2 to pre-install
* 12 up to heroku
*/
const {
join
} = require('path')
const {
config
} = require('dotenv')
const {
ok
} = require('assert')
const env = process.env.NODE_ENV || "dev"
ok(env === "prod" || env === "dev", "environment inválida! Ou prod ou dev")
const configPath = join('./config', `.env.${env}`)
config({
path: configPath
})
const Hapi = require('hapi')
const Context = require('./src/db/strategies/base/contextStrategy')
const MongoDB = require('./src/db/strategies/mongodb/mongoDbStrategy')
const HeroRoutes = require('./src/routes/heroRoutes')
const HeroSchema = require('./src/db/strategies/mongodb/schemas/heroSchema')
const PostgresDB = require('./src/db/strategies/postgres/postgresSQLStrategy')
const AuthRoutes = require('./src/routes/authRoutes')
const UserSchema = require('./src/db/strategies/postgres/schemas/userSchema')
const UtilRoutes = require('./src/routes/utilRoutes')
const HapiSwagger = require('hapi-swagger')
const Inert = require('inert')
const Vision = require('vision')
const HapiJwt = require('hapi-auth-jwt2')
const MINHA_CHAVE_SECRETA = process.env.JWT_KEY
const swaggerConfig = {
info: {
title: '#CursoNodeBR - API Herois',
version: 'v1.0'
},
lang: 'pt'
}
const app = new Hapi.Server({
port: process.env.PORT,
routes: {
cors: true
}
})
function mapRoutes(instance, methods) {
return methods.map(method => instance[method]())
}
async function main() {
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
const connection = MongoDB.connect()
const mongoDb = new Context(new MongoDB(connection, HeroSchema))
await app.register([
HapiJwt,
Inert,
Vision,
{
plugin: HapiSwagger,
options: swaggerConfig
}
])
app.auth.strategy('jwt', 'jwt', {
key: MINHA_CHAVE_SECRETA,
// options: {
// expiresIn: 30
// },
validate: (dado, request) => {
return {
isValid: true
}
}
})
app.auth.default('jwt')
app.route([
...mapRoutes(new UtilRoutes(), UtilRoutes.methods()),
...mapRoutes(new HeroRoutes(mongoDb), HeroRoutes.methods()),
...mapRoutes(new AuthRoutes(MINHA_CHAVE_SECRETA, postgresModel), AuthRoutes.methods())
])
await app.start()
console.log('server running at', app.info.port)
return app;
}
module.exports = main()
================================================
FILE: module-11 - istanbul/mongodb-example.js
================================================
// npm i mongoose
const Mongoose = require('mongoose')
Mongoose.connect('mongodb://erickwendel:minhaoutrasenhasecreta@localhost:27017/herois', {
useNewUrlParser: true
}, (error) => {
if (!error) return;
console.error('error to connect on mongodb', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('db is running!'))
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
nascimento: {
type: Date,
required: true
},
})
const model = Mongoose.model('herois', heroiSchema)
async function main() {
const result = await model.create({
nome: 'Batman',
poder: 'Dinheiro',
nascimento: new Date(1970, 01, 01)
})
console.log('result', result)
const items = await model.find()
console.log('items', items)
}
main()
================================================
FILE: module-11 - istanbul/package.json
================================================
{
"name": "modulo05-multidatabase",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"preinstall": "npm i -g pm2",
"postinstall": "cross-env NODE_ENV=prod npm test",
"prod": "cross-env NODE_ENV=prod pm2-runtime api.js",
"start": "nodemon api.js",
"test": "nyc --reporter=html mocha --timeout 10000 tests/*.test.js --exit"
},
"author": "erickwendel",
"license": "ISC",
"devDependencies": {
"mocha": "^5.2.0",
"nyc": "^13.1.0"
},
"dependencies": {
"bcrypt": "^3.0.2",
"boom": "^7.2.2",
"cross-env": "^5.2.0",
"dotenv": "^6.2.0",
"hapi": "^17.7.0",
"hapi-auth-jwt2": "^8.1.0",
"hapi-swagger": "^9.1.3",
"inert": "^5.1.2",
"joi": "^14.1.0",
"jsonwebtoken": "^8.4.0",
"mongoose": "^5.3.11",
"pg": "^7.4.3",
"pg-hstore": "^2.3.2",
"sequelize": "^4.38.0",
"vision": "^5.4.3"
}
}
================================================
FILE: module-11 - istanbul/postgres-example.js
================================================
// npm i pg
// npm install --save sequelize pg-hstore pg
// const { Client } = require('pg');
// const client = new Client({
// database: 'degfe1gjfh80m8',
// host: 'ec2-54-163-246-5.compute-1.amazonaws.com',
// port: 5432,
// password: 'fea27e438e77e507f6a31e6d8bcc4d8642c88c78b2c7dcc0ec6351d513f43ca8',
// user: 'vwgytcowhvcjug',
// ssl: true,
// });
// (async () => {
// const r = await client.connect();
// console.log('conectado!');
// const res = await client.query('SELECT * FROM TB_HEROIS');
// console.log(res.rows); // Hello world!
// await client.end();
// })();
const Sequelize = require('sequelize');
const sequelize = new Sequelize(
'herois', //database
'erickwendel', // user
'minhasenhasecreta', //senha
{
host: 'localhost',
dialect: 'postgres',
// case sensitive
quoteIdentifiers: false,
// deprecation warning
operatorsAliases: false
// dialectOptions: {
// ssl: true,
// },
},
);
(async () => {
const Herois = sequelize.define(
'herois',
{
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
{
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
},
);
// force: true will drop the table if it already exists
await Herois.sync();
// Table created
const result = await Herois.create({
nome: 'John',
poder: 'Hancock',
});
console.log(
'result',
await Herois.findAll({ raw: true, attributes: ['nome', 'poder', 'id'] }),
);
})();
================================================
FILE: module-11 - istanbul/scripts/mongodb.sh
================================================
use herois
// create
db.herois.create({ nome: 'Iron man', poder: 'Rico'})
// read
db.herois.find({})
// update
db.herois.update({_id: id}, {$set: {nome: 'papaleguas'}})
// delete
db.herois.delete({_id: id})
================================================
FILE: module-11 - istanbul/scripts/postgres.sql
================================================
DROP TABLE IF EXISTS TB_USUARIOS;
CREATE TABLE TB_USUARIOS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
USERNAME TEXT NOT NULL UNIQUE,
PASSWORD TEXT NOT NULL
);
-- create
INSERT INTO TB_USUARIOS
(USERNAME, PASSWORD)
VALUES
('xuxadasilva', '$2b$10$8I99eSf.DcubdihXUXO6weT9iriDG0UIm13d5Ji1TCB1kq88LwZdy');
---
DROP TABLE IF EXISTS TB_HEROIS;
CREATE TABLE TB_HEROIS (
ID INT GENERATED ALWAYS AS IDENTITY PRIMARY KEY NOT NULL,
NOME TEXT NOT NULL,
PODER TEXT NOT NULL
);
-- create
INSERT INTO TB_HEROIS
(NOME, PODER)
VALUES
('Flash', 'Velocidade'),
('Batman', 'Dinheiro'),
('Aquaman', 'Marinho');
-- read
SELECT *
FROM TB_HEROIS;
-- update
UPDATE TB_HEROIS
SET NOME = 'Goku', PODER= 'Deus'
WHERE ID = 1;
--delete
DELETE FROM TB_HEROIS WHERE ID = 2;
================================================
FILE: module-11 - istanbul/server.js
================================================
const http = require('http')
http.createServer((req, res) => {
res.end('Hello node!')
}).listen(4000, () => {
console.log('server rodando!!')
})
================================================
FILE: module-11 - istanbul/src/db/strategies/base/contextStrategy.js
================================================
const IDb = require('./interfaceDb');
class ContextStrategy extends IDb {
constructor(database) {
super();
this._database = database;
}
isConnected() {
return this._database.isConnected();
}
connect() {
return this._database.connect()
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item, upsert) {
return this._database.update(id, item, upsert);
}
delete(id) {
return this._database.delete(id);
}
}
module.exports = ContextStrategy;
================================================
FILE: module-11 - istanbul/src/db/strategies/base/interfaceDb.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class IDb {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
isConnected(id) {
throw new NotImplementedException();
}
}
module.exports = IDb;
================================================
FILE: module-11 - istanbul/src/db/strategies/mongodb/mongoDbStrategy.js
================================================
const ICrud = require('../base/interfaceDb')
const Mongoose = require('mongoose')
const STATUS = {
0: 'Disconectado',
1: 'Conectado',
2: 'Conectando',
3: 'Disconectando',
}
class MongoDB extends ICrud {
// 3o
constructor(connection, schema) {
super()
// 4o
this._connection = connection;
this._collection = schema;
}
// 2o
async isConnected() {
const state = STATUS[this._connection.readyState]
if (state === 'Conectado') return state;
if (state !== 'Conectando') return state
await new Promise(resolve => setTimeout(resolve, 1000))
return STATUS[this._connection.readyState]
}
// 1o
static connect() {
Mongoose.connect(process.env.MONGO_URL, {
useNewUrlParser: true
}, function (error) {
if (!error) return;
console.log('Falha na conexão!', error)
})
const connection = Mongoose.connection
connection.once('open', () => console.log('database rodando!!'))
return connection;
}
async create(item) {
return this._collection.create(item)
}
async read(item = {}) {
return this._collection.find(item, {
nome: 1,
poder: 1,
insertedAt: 1
})
}
async update(id, item) {
return this._collection.updateOne({
_id: id
}, {
$set: item
})
}
async delete(id) {
return this._collection.deleteOne({
_id: id
})
}
}
module.exports = MongoDB
================================================
FILE: module-11 - istanbul/src/db/strategies/mongodb/schemas/heroSchema.js
================================================
const Mongoose= require('mongoose')
const heroiSchema = new Mongoose.Schema({
nome: {
type: String,
required: true
},
poder: {
type: String,
required: true
},
insertedAt: {
type: Date,
default: new Date()
}
})
//mocha workaround
module.exports = Mongoose.models.herois || Mongoose.model('herois', heroiSchema)
================================================
FILE: module-11 - istanbul/src/db/strategies/postgres/postgresSQLStrategy.js
================================================
const IDb = require('../base/interfaceDb');
const Sequelize = require('sequelize');
class PostgreSQLStrategy extends IDb {
constructor(connection, schema) {
super();
this._db = schema;
this._connection = connection;
}
static async defineModel(connection, schema) {
const model = connection.define(
schema.name, schema.schema, schema.options,
);
await model.sync()
return model
}
static async connect() {
const sequelize = new Sequelize(process.env.POSTGRES_URL, {
quoteIdentifiers: false,
ssl: process.env.SSL_DB,
dialectOptions: {
ssl: process.env.SSL_DB,
},
// deprecation warning
operatorsAliases: false,
//disable logging
logging: false
})
return sequelize
}
async isConnected() {
try {
// await this._connect();
await this._connection.authenticate();
return true;
} catch (error) {
console.error('fail!', error);
return false;
}
}
create(item) {
return this._db.create(item, {
raw: true
});
}
read(item) {
return this._db.findAll({
where: item,
raw: true
});
}
update(id, item, upsert = false) {
const fn = upsert ? 'upsert' : 'update'
return this._db[fn](item, {
where: {
id
}
});
}
delete(id) {
const query = id ? {
id
} : {};
return this._db.destroy({
where: query
});
}
}
module.exports = PostgreSQLStrategy;
================================================
FILE: module-11 - istanbul/src/db/strategies/postgres/schemas/heroiSchema.js
================================================
const Sequelize = require('sequelize')
const HeroiSchema = {
name: 'herois',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
nome: {
type: Sequelize.STRING,
required: true,
},
poder: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_HEROIS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = HeroiSchema
================================================
FILE: module-11 - istanbul/src/db/strategies/postgres/schemas/userSchema.js
================================================
const Sequelize = require('sequelize')
const UserSchema = {
name: 'users',
schema: {
id: {
type: Sequelize.INTEGER,
required: true,
primaryKey: true,
autoIncrement: true,
},
username: {
type: Sequelize.STRING,
unique: true,
required: true,
},
password: {
type: Sequelize.STRING,
required: true,
},
},
options: {
//opcoes para base existente
tableName: 'TB_USUARIOS',
freezeTableName: false,
timestamps: false,
}
}
module.exports = UserSchema
================================================
FILE: module-11 - istanbul/src/example1.js
================================================
class NotImplementedException extends Error {
constructor() {
super('Not Implemented Exception');
}
}
//interface
class ICrud {
create(item) {
throw new NotImplementedException();
}
read(item) {
throw new NotImplementedException();
}
update(id, item) {
throw new NotImplementedException();
}
delete(id) {
throw new NotImplementedException();
}
}
class MongoDBStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('MongoDBStrategy');
}
}
class PostgreSQLStrategy extends ICrud {
constructor() {
super();
}
create(item) {
console.log('PostgreSQLStrategy');
}
}
class ContextoStrategy extends ICrud {
constructor(database) {
super();
this._database = database;
}
create(item) {
return this._database.create(item);
}
read(item) {
return this._database.read(item);
}
update(id, item) {
return this._database.update(id, item);
}
delete(id) {
return this._database.delete(id, item);
}
}
const contextMongo = new ContextoStrategy(new MongoDBStrategy());
contextMongo.create();
const context = new ContextoStrategy(new PostgreSQLStrategy());
context.create();
context.read();
================================================
FILE: module-11 - istanbul/src/helpers/passwordHelper.js
================================================
const Bcrypt = require('bcrypt')
const {
promisify
} = require('util')
const hashAsync = promisify(Bcrypt.hash)
const compareAsync = promisify(Bcrypt.compare)
const SALT = parseInt(process.env.PWD_SALT)
class Password {
static hashPassword(pass) {
return hashAsync(pass, SALT)
}
static comparePassword(pass, hash) {
return compareAsync(pass, hash)
}
}
module.exports = Password
================================================
FILE: module-11 - istanbul/src/routes/authRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
const Boom = require('boom')
const PasswordHelper = require('./../helpers/passwordHelper')
const USER = {
username: 'xuxadasilva',
password: '123'
}
const Jwt = require('jsonwebtoken')
class AuthRoutes extends BaseRoute {
constructor(key, db) {
super()
this.secret = key
this.db = db
}
login() {
return {
path: '/login',
method: 'POST',
config: {
auth: false,
tags: ['api'],
description: 'fazer login',
notes: 'retorna o token',
validate: {
payload: {
username: Joi.string().required(),
password: Joi.string().required()
}
}
},
handler: async (request, headers) => {
const {
username,
password
} = request.payload
const [user] = await this.db.read({
username: username.toLowerCase()
})
if (!user) {
return Boom.unauthorized('O usuario informado nao existe')
}
const match = await PasswordHelper.comparePassword(password, user.password)
if (!match) {
return Boom.unauthorized('O usuario e senha invalidos!')
}
// if (
// username.toLowerCase() !== USER.username ||
// password !== USER.password
// )
// return Boom.unauthorized()
return {
token: Jwt.sign({
username: username
}, this.secret)
}
}
}
}
}
module.exports = AuthRoutes
================================================
FILE: module-11 - istanbul/src/routes/base/baseRoute.js
================================================
class BaseRoute {
static methods() {
return Object.getOwnPropertyNames(this.prototype)
.filter(method => method !== 'constructor' && !method.startsWith('_'))
}
}
module.exports = BaseRoute
================================================
FILE: module-11 - istanbul/src/routes/heroRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const Joi = require('joi')
class HeroRoutes extends BaseRoute {
constructor(db) {
super()
this.db = db
}
list() {
return {
path: '/herois',
method: 'GET',
config: {
tags: ['api'],
description: 'listar herois',
notes: 'retorna a base inteira de herois',
validate: {
headers: Joi.object({
authorization: Joi.string().required()
}).unknown()
}
},
handler: (request, headers) => {
return this.db.read()
}
}
}
create() {
return {
path: '/herois',
method: 'POST',
config: {
tags: ['api'],
description: 'cadastrar herois',
notes: 'Cadastra um heroi por nome e poder',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
payload: {
nome: Joi.string().max(100).required(),
poder: Joi.string().max(30).required()
}
},
},
handler: (request, headers) => {
const payload = request.payload
return this.db.create(payload)
}
}
}
update() {
return {
path: '/herois/{id}',
method: 'PATCH',
config: {
tags: ['api'],
description: 'atualizar herois',
notes: 'atualiza um heroi por ID',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
},
payload: {
nome: Joi.string().max(100),
poder: Joi.string().max(30)
}
},
},
handler: (request, headers) => {
const payload = request.payload;
const id = request.params.id;
return this.db.update(id, payload)
}
}
}
delete() {
return {
path: '/herois/{id}',
method: 'DELETE',
config: {
tags: ['api'],
description: 'remover herois',
notes: 'remove um heroi por id',
validate: {
failAction: (request, h, err) => {
throw err;
},
headers: Joi.object({
authorization: Joi.string().required()
}).unknown(),
params: {
id: Joi.string().required()
}
}
},
handler: (request, headers) => {
const id = request.params.id;
return this.db.delete(id)
}
}
}
}
module.exports = HeroRoutes
================================================
FILE: module-11 - istanbul/src/routes/utilRoutes.js
================================================
const BaseRoute = require('./base/baseRoute')
const {
join
} = require('path')
/*
1o add nyc
2o npm t
3o create utilRoutes
4o register on api
5o run on navigator
6o add .gitignore
7o add --exit to npm t
8o add postinstall
*/
class UtilRoutes extends BaseRoute {
coverage() {
return {
path: '/coverage/{param*}',
method: 'GET',
config: {
auth: false,
},
handler: {
directory: {
path: join(__dirname, '../../coverage'),
redirectToSlash: true,
index: true,
},
},
}
}
}
module.exports = UtilRoutes
================================================
FILE: module-11 - istanbul/tests/apiHeroes.test.js
================================================
const assert = require('assert')
const api = require('./../api')
let app = {}
let MOCK_ID = ""
let MOCK_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6Inh1eGFkYXNpbHZhIiwiaWF0IjoxNTQyNzI4MzQ0fQ.JvBOZa7yXds4ktQ7HvNRYO6-s1mbU7AKTJP9G2ghje4"
const headers = {
Authorization: MOCK_TOKEN
}
function cadastrar() {
return app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
nome: 'Flash',
poder: 'Velocidade'
}
});
}
describe('API Heroes test suite', function () {
this.beforeAll(async () => {
app = await api
const result = await cadastrar()
MOCK_ID = JSON.parse(result.payload)._id
})
it('não deve listar herois sem um token', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
it('listar /heroes', async () => {
const result = await app.inject({
method: 'GET',
url: '/herois',
headers
})
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(Array.isArray(JSON.parse(result.payload)))
})
it('cadastrar /herois', async () => {
const result = await cadastrar()
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nome, "Flash")
})
it('não deve cadastrar com payload errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/herois',
headers,
payload: {
NAME: 'Flash'
}
})
const payload = JSON.parse(result.payload)
assert.deepEqual(result.statusCode, 400)
assert.ok(payload.message.search('"nome" is required') !== -1)
})
it('atualizar /herois/{id}', async () => {
const result = await app.inject({
method: 'PATCH',
url: `/herois/${MOCK_ID}`,
headers,
payload: {
nome: 'Canário Negro',
poder: 'Grito'
}
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).nModified, 1)
})
it('remover /herois/{id}', async () => {
const result = await app.inject({
method: 'DELETE',
url: `/herois/${MOCK_ID}`,
headers,
})
assert.deepEqual(result.statusCode, 200)
assert.deepEqual(JSON.parse(result.payload).n, 1)
})
})
================================================
FILE: module-11 - istanbul/tests/auth.test.js
================================================
//1o criar test
//2o criar passwordHelper
//3o gerar senha e guardar
//4o criar model de usuario
//5o adicionar chamada em api.js
//6o adicionar no construtor de auth receber o model
//7o criar logica na route
//8o adicionar upsert no context e postgresStrategy
//9o adicionar no arquivo postgres.sql o script para criar a tabela
const assert = require('assert')
const api = require('../api')
const Context = require('./../src/db/strategies/base/contextStrategy')
const PostgresDB = require('./../src/db/strategies/postgres/postgresSQLStrategy')
const UserSchema = require('./../src/db/strategies/postgres/schemas/userSchema')
let app = {}
const USER = {
username: 'xuxadasilva',
password: '321123'
}
const USER_DB = {
...USER,
password: '$2b$04$SdlyEJsy.o5UgsgVr5csJ.ralZVyPviGH80BOb0zJCTSis30RB8Ba'
}
describe('Auth test suite', function () {
this.beforeAll(async () => {
app = await api
const connectionPostgres = await PostgresDB.connect()
const model = await PostgresDB.defineModel(connectionPostgres, UserSchema)
const postgresModel = new Context(new PostgresDB(connectionPostgres, model));
await postgresModel.update(null, USER_DB, true)
})
it('deve obter um token', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: USER
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 200)
assert.ok(JSON.parse(result.payload).token.length > 10)
})
it('deve retornar não autorizado ao tentar obter um token com login errado', async () => {
const result = await app.inject({
method: 'POST',
url: '/login',
payload: {
username: 'erickwendel',
password: '123'
}
});
const statusCode = result.statusCode
assert.deepEqual(statusCode, 401)
assert.deepEqual(JSON.parse(result.payload).error, "Unauthorized")
})
})
================================================
FILE: module-11 - istanbul/tests/mongodbStrategy.test.js
================================================
const assert = require('assert')
const MongoDb = require('../src/db/strategies/mongodb/mongoDbStrategy')
const HeroSchema = require('../src/db/strategies/mongodb/schemas/heroSchema')
const Context = require('../src/db/strategies/base/contextStrategy')
// 1o alterar criar pasta mongodb
// 2o mover mongodbStrategy para mongodb
// 3o modificar classe do mongodbStrategy
// 4o modificar criar schema em mongodb/schemas
// 6o modificar teste fazendo conexão direto do MongoDB
// 5o modificar teste passando para o MongoDB
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Maravilha',
poder: 'força'
};
let MOCK_HEROI_ATUALIZAR_ID = '';
let context = {}
describe('MongoDB Suite de testes', function () {
this.beforeAll(async () => {
const connection = MongoDb.connect()
context = new Context(new MongoDb(connection, HeroSchema))
const result = await context.create(MOCK_HEROI_ATUALIZAR)
MOCK_HEROI_ATUALIZAR_ID = result._id
})
it('verificar conexao', async () => {
const result = await context.isConnected()
const expected = 'Conectado'
assert.deepEqual(result, expected)
})
it('cadastrar', async () => {
const {
nome,
poder
} = await context.create(MOCK_HEROI_CADASTRAR)
assert.deepEqual({
nome,
poder
}, MOCK_HEROI_CADASTRAR)
})
it('listar', async () => {
const [{
nome,
poder
}] = await context.read({
nome: MOCK_HEROI_CADASTRAR.nome
})
const result = {
nome,
poder
}
assert.deepEqual(result, MOCK_HEROI_CADASTRAR)
})
it('atualizar', async () => {
const result = await context.update(MOCK_HEROI_ATUALIZAR_ID, {
poder: 'Laço'
})
assert.deepEqual(result.nModified, 1)
})
it('remover', async () => {
const result = await context.delete(MOCK_HEROI_ATUALIZAR_ID)
assert.deepEqual(result.n, 1)
})
})
================================================
FILE: module-11 - istanbul/tests/passwordHelper.test.js
================================================
const assert = require('assert');
const PasswordHelper = require('../src/helpers/passwordHelper');
const SENHA = 'erick@32123';
const HASH = '$2b$04$nJuOS9YZH9FpsKTOSh2IPOZUW9IF83bo54FE2L/rO/Xzrl.pS/qV2'
describe('UserHelper test suite', function () {
it('deve gerar um hash a partir de uma senha', async () => {
const result = await PasswordHelper.hashPassword(SENHA);
// const result = await PasswordHelper.hashPassword('321123');
// console.log('result', result)
assert.ok(result.length > 10);
});
it('deve comparar uma senha e seu hash', async () => {
const result = PasswordHelper.comparePassword(SENHA, HASH)
assert.ok(result)
})
});
================================================
FILE: module-11 - istanbul/tests/postgresStrategy.test.js
================================================
const {
equal,
deepEqual,
ok
} = require('assert');
const PostgresStrategy = require('../src/db/strategies/postgres/postgresSQLStrategy');
const HeroiSchema = require('../src/db/strategies/postgres/schemas/heroiSchema');
const Context = require('../src/db/strategies/base/contextStrategy');
const MOCK_HEROI_CADASTRAR = {
nome: 'Gaviao Negro',
poder: 'flexas'
};
const MOCK_HEROI_ATUALIZAR = {
nome: 'Mulher Gavião',
poder: 'grito'
};
let context = {}
describe('PostgreSQL Strategy', function () {
this.timeout(Infinity);
before(async () => {
const connection = await PostgresStrategy.connect()
const model = await PostgresStrategy.defineModel(connection, HeroiSchema)
context = new Context(new PostgresStrategy(connection, model));
await context.delete();
await context.create(MOCK_HEROI_CADASTRAR);
await context.create(MOCK_HEROI_ATUALIZAR);
});
it('PostgresSQL connection', async () => {
const result = await context.isConnected();
equal(result, true);
});
it('cadastrar', async () => {
const result = await context.create(MOCK_HEROI_CADASTRAR);
delete result.dataValues.id;
deepEqual(result.dataValues, MOCK_HEROI_CADASTRAR);
});
it('listar', async () => {
const [result] = await context.read(MOCK_HEROI_CADASTRAR);
delete result.id;
deepEqual(result, MOCK_HEROI_CADASTRAR);
});
it('atualizar', async () => {
const [result] = await context.read({});
const novoItem = {
...MOCK_HEROI_CADASTRAR,
nome: 'Mulher Maravilha',
};
const [update] = await context.update(result.id, novoItem);
deepEqual(update, 1);
});
it('remover', async () => {
const [item] = await context.read({});
const result = await context.delete(item.id);
deepEqual(result, 1);
});
});