├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── S03E01.md ├── S03E02.md ├── S03E03.md ├── S03E04.md ├── S03E05.md ├── S03E06.md ├── S03E07.md ├── S03E08.md └── img ├── a-clockwork-orange-puremovies-620x299.jpg ├── s03e06.png └── vue-js-devtools.png /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Regras de conduta para participantes do Hellojs 2 | 3 | Essas são as regras de conduta para que não aconteça nenhum transtorno por parte dos(as) envolvidos(as) em nossos projetos. 4 | 5 | O Hellojs é um curso aberto a todos e todos devem se sentir confortáveis participando de nossas iniciativas. 6 | 7 | Não toleramos nenhum tipo de repúdio, humilhação ou discriminação por: 8 | 9 | * Gênero, identidade de gênero ou expressão de gênero; 10 | * Orientação sexual; 11 | * Restrições físicas; 12 | * Aparência física (incluindo, mas não limitado, ao tamanho do corpo); 13 | * Raça e/ou etnia; 14 | * Idade; 15 | * Religião ou a falta dela; 16 | * Escolha de tecnologias; 17 | 18 | Como membro deste grupo, você concorda que: 19 | 20 | * Nós somos, coletivamente e individualmente, comprometidos com a segurança e inclusão; 21 | * Nós adotamos a política de tolerância zero para assédios, perseguições ou discriminações; 22 | * Nós respeitamos limites, identidade e privacidade das pessoas; 23 | * Nós nos abstemos de usar linguagem que possa ser considerada opressiva, como comentários sexistas, racistas, homofóbicos, transfóbicos, classistas ou que discrimine pessoas com qualquer tipo de deficiência, mas este Código de Conduta não está limitado a apenas estes; 24 | * Nós evitamos tópicos ofensivos como forma de humor. 25 | 26 | Nós trabalhamos ativamente para: 27 | 28 | * Ser uma comunidade segura; 29 | * Cultivar uma rede de suporte e encorajamento para todos; 30 | * Encorajar variadas formas de expressão de maneira responsável. 31 | 32 | Nós condenamos: 33 | 34 | * Perseguição, _doxxing_ (investigar a vida de uma pessoa sem autorização) ou publicações indevidas de informações privadas; 35 | * Ameaça e assédio de qualquer tipo; 36 | * Qualquer comportamento que comprometa a segurança dos demais membros. 37 | 38 | **Essas atitudes NÃO SÃO CORRETAS.** Se você não concorda com estas regras, por favor, cancele sua inscrição neste grupo. 39 | 40 | O desrespeito às regras desta comunidade, descritas nesse documento, acarretará em consequências: 41 | 42 | - Publicações que não estiverem de acordo com este Código de Conduta serão removidas; 43 | - Cabe aos moderadores decidir se você será removido temporariamente ou permanentemente deste grupo. 44 | 45 | **Se você sofrer algum tipo de abuso, assédio, discriminação ou se sentir inseguro, fale com um moderador. Se o moderador for a pessoa que você quer reportar, fale com outro moderador.** 46 | 47 | *A posição de moderador é para fins de moderação imparcial; eles não vão moderar ou editar o conteúdo postado pelos membros do grupo para outras finalidades ou por motivos estritamente pessoais.* 48 | 49 | ## Moderadores 50 | 51 | * [Leonardo Silveira](https://github.com/sombriks) 52 | * [Yuri Oliveira](https://github.com/yuriploc) 53 | 54 | --- 55 | 56 | *Esse texto é um documento em constante edição, e pode ser alterado no futuro.* 57 | 58 | Código de conduta baseado em: https://github.com/fnando/codigo-de-conduta, https://github.com/AndroidDevBR/Codigo-De-Conduta 59 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | https://creativecommons.org/licenses/by/4.0/ 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Hello.js 2 | 3 | **Esse é um documento vivo, portanto está em constante mutação.** 4 | 5 | - O Hello.js surgiu em ~2015-11-28, quando @sombriks e @yuriploc tiveram de realizar **dois** projetos para a disciplina de Projeto Social do IFCE. 6 | 7 | ## Histórico 8 | 9 | - Com a ajuda do Centro Acadêmico (CA), o projeto foi executado e os responsáveis foram aprovados na cadeira :books:. Desde então, Hello.js transformou-se em um projeto com a intenção de oferecer treinamentos práticos e rápidos sobre como tornar-se um desenvolvedor `fullstack`. As duas edições _out of the box/chair_ foram em 2016. 10 | 11 | ## Modelo de aplicação do curso 12 | 13 | - 8 aulas _at full speed_ :fire: 14 | - O curso será [gamificado](https://en.wikipedia.org/wiki/Gamification). Cada semana terá pelo menos um desafio, e **todos** os participantes deverão, pelo menos, _tentar_ realizar o(s) desafio(s) proposto(s), subindo um repositório no GitHub. 15 | - Os desafios podem ser parecidos com o que se pede no [Treinamento TechPar](https://gist.github.com/sombriks/82d4b9b41b1281b392ac32fac4fbba61) 16 | - O participante que não submeter código dentro do prazo não poderá participar da semana seguinte. Isso impede que os turistas continuem frequentando as aulas seguintes simplesmente por [hábito](http://study.com/articles/20_Bad_Habits_That_Dont_Belong_in_College.html), em vez de [estudar e programar](http://www.educationcorner.com/habits-of-successful-students.html). 17 | 18 | ## Ementa 19 | 20 | - [Aula 1](S03E01.md) 21 | - apresentações - 10m 22 | - git - 10m 23 | - GitHub - 20m 24 | - console - 20m 25 | - nodejs - 20m 26 | - editor de texto - 10m 27 | 28 | - [Aula 2](S03E02.md) 29 | - npm/package.json - 15m 30 | - JavaScript ES6 server-side - 40m 31 | - Expressjs - 25m 32 | - Axios - 10min 33 | 34 | - [Aula 3](S03E03.md) 35 | - sqlite/dbbrowser 20m 36 | - SQL - 30m 37 | - knex - 20m 38 | - knex migrations - 20m 39 | 40 | - [Aula 4](S03E04.md) 41 | - combinando knex, knex migrations e express - 30m 42 | - pasta static do express - 10m 43 | - HTML - 10m 44 | - JavaScript client-side - 40m 45 | 46 | - [Aula 5](S03E05.md) 47 | - CSS - 30m 48 | - vuejs - 30m 49 | - axios - 30m 50 | - ~~browserify - 20m~~ 51 | 52 | - [Aula 6](S03E06.md) 53 | - projeto fullstack com browserify - 20m 54 | - budo - 10m 55 | - vue-material - 30m 56 | - google material icons - 10m 57 | - render function e single file components - 20m 58 | - ~~font-awesome-icons - 20m~~ 59 | 60 | - [Aula 7](S03E07.md) 61 | - projeto client com SPA (single page applications) - 10m 62 | - ~~conceitos do desenvolvimento fullstack - 20m~~ 63 | - ~~padrões de projetos em javascript - 20m~~ 64 | - levantamento de requisitos - 30m 65 | - ferramentas de acompanhamento de projeto - 30m 66 | 67 | - [Aula 8](S03E08.md) 68 | - boas práticas e padrões de projeto em javascript - 25m 69 | - projeto showcase de trabalho - 65m 70 | 71 | ## Estrutura necessária 72 | 73 | - laboratório com, no mínimo, 10 computadores funcionando e com acesso à internet. 74 | - pode-se ter até 2 participantes por pc 75 | - acesso liberado para os instrutores e os participantes durante a duração o minicurso 76 | - os seguintes softwares instalados e configurados (para computadores windows) 77 | - node.js 6 ou superior 78 | - npm 3 ou superior (vem com o instalador do node) 79 | - knex instalado a nível de sistema (npm -g install knex) 80 | - budo (npm -g install budo) 81 | - browserify (npm -g install browserify) 82 | - nodemon (npm -g install nodemon) 83 | - code (Visual Studio Code) 84 | - google chrome 85 | - postgresql 9.5 ou superior 86 | - usuario administrativo 'postgres' com senha 'postgres' 87 | - pgadmin 3 (o 4 não presta) 88 | - sqlite dbbrowser 89 | 90 | ## Participantes da edição 3.0.0 91 | 92 | - a lista de inscritos já foi circulada na thread de email que trata da organização destas oficinas 93 | - temos 40 inscritos, número recorde 94 | - eles serão divididos em grupos de 20, que é o número aceitável de pessoas dentro do laboratório 95 | 96 | ## Proposta de datas e laboratórios 97 | 98 | - conforme o [calendário acadêmico](http://ifce.edu.br/fortaleza/calendario): 99 | - ~~de 2017-07-03 a 2017-07-12~~ 100 | - ~~de 2017-07-10 a 2017-07-19~~ 101 | - ~~de 2017-07-24 a 2017-08-02~~ 102 | - ~~de 2017-08-28 a 2017-09-06~~ 103 | - Turma 1 104 | - dias 05, 12, 13, 19, 20, 26 e 27 de setembro de 2017 105 | - dia 03 de outubro de 2017 106 | - Turma 2 107 | - dias 04, 10, 11, 17, 18, 24, 25 e 31 de outubro de 2017 108 | - Dias de terça-feira o laboratório será o LMC 3 109 | - Dias de quarta-feira o laboratório será o LMC 2 110 | 111 | ## Horário 112 | 113 | - das 18:30 às 20:00 114 | 115 | ## Responsáveis pela realização do minicurso 116 | 117 | - Prof. Antônio Serra - IFCE (professor apoiando o projeto) - prof.serra@gmail.com 118 | - Al. Leonardo Silveira - IFCE (facilitador das aulas) - sombriks@gmail.com 119 | - B.el Yuri Soares - Formado pelo IFCE (facilitador das aulas) - yuri@matsya.io 120 | 121 | ## Segunda edição 122 | 123 | - temos aproximadamente 40 inscritos e para evitarmos injustiças planejamos duas edições 124 | - ~~a segunda edição trataremos num momento posterior~~ a segunda edição é imediatamente após o fim da primeira 125 | 126 | ## Motivação 127 | 128 | - os alunos da engenharia de computação podem se beneficiar deste conhecimento extra 129 | - as tecnologias a serem apresentadas sáo escolhidas direto do mercado atual 130 | - a demanda por profisionais aptos a desenvolver e entregar sistemas web só cresce 131 | 132 | ## Resultados esperados 133 | 134 | - mais um grupo de alunos que estarão aptos a entregar soluões de software dentro de um tempo aceitável 135 | - repetir ou superar os resultados da versão 2 do minicurso, com 2 alunos encaminhados para o mercado de trabalho, uma visita de um headhunter em sala no último dia e tantos outros tocando projetos no github, fazendo portfólio, após o minicurso. 136 | -------------------------------------------------------------------------------- /S03E01.md: -------------------------------------------------------------------------------- 1 | # HelloJS 3.0.0 chapter 1 2 | 3 | ## Intro 4 | 5 | ### Quem somos 6 | 7 | [@sombriks](https://github.com/sombriks) 8 | 9 | [@yuriploc](https://github.com/yuriploc) :space_invader: 10 | 11 | ### O que estamos fazendo aqui :thinking: 12 | 13 | Desafios 14 | - Fullstack em 8 aulas? 15 | 16 | Soluções 17 | - DiY 18 | - KISS 19 | - Practice, practice, practice! 20 | 21 | Prazos 22 | - One date to rule 'em all :fire: 23 | 24 | ## Git 25 | 26 | ```shell 27 | git remote -v 28 | git fetch origin --prune 29 | git checkout master 30 | git pull origin 31 | git checkout -b feature/326-create-magic-function 32 | git status 33 | git diff -w 34 | git log 35 | git commit -a 36 | git push origin feature/326-create-magic-function 37 | ``` 38 | 39 | ## GitHub 40 | 41 | - CV Hipster moderno 42 | - Stars 43 | - Forks 44 | - Issues 45 | - Pull Requests 46 | - GitHub Pages (`user`.github.io) 47 | 48 | ## Consoles 49 | 50 | ```shell 51 | $ npm -version 52 | $ node -v 53 | $ npm i 54 | ``` 55 | 56 | ctrl+shift+i 57 | 58 | ```javascript 59 | console.log('Ops!') 60 | ``` 61 | 62 | ## NodeJS 63 | 64 | É browser? 65 | 66 | `$ node` 67 | 68 | ```javascript 69 | console.log('Ops!') 70 | ``` 71 | 72 | É V8! 73 | 74 | [Slack](https://slack.com/downloads/linux), [Atom](https://atom.io), [VS Code](https://code.visualstudio.com/), [Tessel (IoT)](https://www.tessel.io/), [NASA](https://nasa.github.io/openmct/) :rocket: 75 | 76 | ## Editor de texto 77 | 78 | - [Atom](https://atom.io), 79 | - [VS Code](https://code.visualstudio.com/), 80 | - [VIM](https://vim.sourceforge.io/) :sweat_smile: 81 | 82 | ## Desafio 83 | 84 | Crie um repositório chamado hellojs-s03e01 e adicione um README.md 85 | -------------------------------------------------------------------------------- /S03E02.md: -------------------------------------------------------------------------------- 1 | # HelloJS 3.0.0 chapter 2 2 | 3 | # NPM :wrench: 4 | 5 | - Gerenciador de pacotes 6 | ```shell 7 | mkdir hellojs-s03e02; cd hellojs-s03e02 8 | npm init 9 | ``` 10 | 11 | `cat package.json` 12 | ```javascript 13 | { 14 | "name": "hellojs-s03e02", 15 | "version": "0.1.0", 16 | "description": "My first package", 17 | "main": "index.js", 18 | "scripts": { 19 | "test": "mocha" 20 | }, 21 | "keywords": [ 22 | "test", 23 | "hellojs" 24 | ], 25 | "author": "wee", 26 | "license": "MIT" 27 | } 28 | ``` 29 | 30 | - Registro público de pacotes 31 | - Instalado junto com o Node.js 32 | 33 | ```shell 34 | [~] node -v && npm -v 35 | v6.11.3 36 | 3.10.10 37 | [~] node -v && npm -v 38 | v8.4.0 39 | 5.4.1 40 | ``` 41 | 42 | [Tabela LTS](https://github.com/nodejs/LTS#lts-schedule1) do Node.js 43 | 44 | - Resolve dependências 45 | 46 | `npm i lodash` 47 | 48 | - Facilita compartilhar código 49 | 50 | [Jeff Lembeck: Package Quest - The journey of a package from the npm registry to your computer](https://www.youtube.com/watch?v=8vtVmLviiGQ&t=16430s) 51 | 52 | # JavaScript ES6+ (server-side) 53 | 54 | ![Full Speed](img/a-clockwork-orange-puremovies-620x299.jpg) 55 | 56 | [ES6 Features](http://es6-features.org/) 57 | 58 | ### Variáveis 59 | 60 | ```javascript 61 | var x = 2 62 | let y = 3 63 | const z = 4 64 | ``` 65 | 66 | - **var** é escopo de instância. E é velho (a.k.a. *feio*) também, faz evangelista chorar baixinho 67 | - **let** é escopo de bloco. É bonito. Usem 68 | - **const** é de bloco e imutável. A peruada do funcional curte 69 | 70 | ### Estruturas de controle 71 | 72 | ```javascript 73 | let a = 10; 74 | let b = 20; 75 | let m = 10; 76 | let i = 10; 77 | let k = 10; 78 | 79 | if(a > b) { 80 | // ... 81 | } 82 | 83 | switch(m) { 84 | case 5: 85 | // ... 86 | break; 87 | case 10: 88 | // ... 89 | break; 90 | case 15: 91 | // ... 92 | break; 93 | default: 94 | // ... 95 | break; 96 | } 97 | 98 | for(let j = 0 ; j < 10 ; j++ ) { 99 | // ... 100 | } 101 | 102 | while(i-->0) { 103 | console.log(i); 104 | } 105 | 106 | do { 107 | // ... 108 | k = k -1; 109 | } while(k); 110 | ``` 111 | 112 | - Os valores **0, "", null** e **undefined** funcionam como **false** também 113 | - excetuando o switch, o bloco é opcional se executarmos uma única instrução 114 | 115 | ### Funções 116 | 117 | ```javascript 118 | function soma(x,y) { 119 | return x + y; 120 | } 121 | 122 | const soma = function(x,y) { 123 | return x + y; 124 | } 125 | 126 | const soma = (x,y) => { 127 | return x + y; 128 | } 129 | 130 | const soma = (x,y) => x + y 131 | ``` 132 | 133 | - funções tem os mesmos direitos de variáveis 134 | - funções podem ser argumentos de outras funções 135 | 136 | ```javascript 137 | function foo(x) { 138 | console.log(x); 139 | } 140 | 141 | function bar(x,y) { 142 | x(y); 143 | } 144 | 145 | // uso: 146 | 147 | bar(foo,2) 148 | // imprime 2 149 | 150 | bar(console.log,2); 151 | // imprime 2 do mesmo jeito 152 | 153 | // pode ser anônima também: 154 | bar(function(x){ 155 | console.log(x*x); 156 | },2); 157 | ``` 158 | 159 | - importante observar o escopo de execução (falamos adiante) 160 | - exótico? conheça agora a fat arrow 161 | 162 | ```javascript 163 | function bar(x,y){ 164 | x(y); 165 | } 166 | 167 | bar((x) => console.log(x) ,2) 168 | // imprime 2 169 | 170 | // na fat arrow function o retorno é o corpo da função. Exemplo: 171 | 172 | function compara(a,b){ 173 | return a - b; 174 | } 175 | 176 | let lista = [2,1,3]; 177 | 178 | lista.sort(compara); 179 | // [1,2,3] 180 | 181 | lista.sort((a,b) => a - b) 182 | // [1,2,3] do mesmo jeito 183 | ``` 184 | 185 | - a fat arrow existe nos navegadores mais recentes 186 | - não cria escopo especial como as funções passadas por parâmetro fazem (o 'this' está correto) 187 | 188 | ### Coleções (mapas e listas) 189 | 190 | ```javascript 191 | var lista1 = []; 192 | lista1.push(1); 193 | // [1] 194 | lista1.push("Arroz"); 195 | // [1,"Arroz"] 196 | lista1.push({a:2}); 197 | // [1,"Arroz",{a:2}] 198 | lista1.push([2,3,4]); 199 | // [1,"Arroz",{a:2},[2,3,4]] 200 | lista1.pop(); 201 | // [1,"Arroz",{a:2}] 202 | lista1.shift(); 203 | // ["Arroz",{a:2}] 204 | lista1.unshift(4); 205 | // [4,"Arroz",{a:2}] 206 | lista1.length; 207 | // 3 208 | 209 | var mapa1 = {a:1}; 210 | mapa1.b=2; 211 | mapa1.c={d:3}; 212 | // {a:1, b:2, c:{d:3}} 213 | ``` 214 | 215 | - listas tem o atributo especial **.length** que diz o tamanho delas 216 | - você pode inserir qualquer coisa em listas e mapas. Aqui não tem frescura 217 | 218 | ```javascript 219 | var lista2 = [5,10,15,20,25,30,35] 220 | var mapa2 = {a:1,b:2,c:3,d:4} 221 | 222 | for(let x in lista2) 223 | console.log(lista2[x]); 224 | // 5,10,15,20,25,30,35 225 | for(let y in mapa2) 226 | console.log("%s: %s, ",y,mapa2[y]) 227 | // a: 1, b: 2, c: 3, d: 4, 228 | console.log("a" in mapa2) 229 | // true 230 | console.log("e" in mapa2) 231 | // false 232 | ``` 233 | 234 | - mapas e listas tem direito a sintaxe especial no **for** 235 | - o **in** funciona como operador pra testar a existência do membro 236 | 237 | ### O .filter e o .map e a beleza 238 | 239 | ```javascript 240 | const list1 = [1,2,3,4,5,6,7,8,9] 241 | // 242 | list1.filter(function (e) { 243 | return e > 4 244 | }) 245 | // [5,6,7,8,9] 246 | list1.filter(e => e % 2 == 0) 247 | // [2,4,6,8] 248 | list1.map(x => x * 3) 249 | // [ 3, 6, 9, 12, 15, 18, 21, 24, 27 ] 250 | list1.map(c => { 251 | c = c + "x" + c 252 | return c 253 | }) 254 | // [ '1x1', '2x2', '3x3', '4x4', '5x5', '6x6', '7x7', '8x8', '9x9' ] 255 | ``` 256 | 257 | - iteram a lista (mais charmoso que 'for') 258 | - devolvem uma nova lista 259 | - [Mais detalhes aqui](https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 260 | 261 | ```javascript 262 | const list2 = [1,1,2,3,4,5,5,4,5,6,7,8,9,8] 263 | list2.filter((e,i) => list2.indexOf(e) == i) 264 | // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ] 265 | ``` 266 | 267 | 268 | ### Um pouco de orientação a objetos e o **this** (os problemas relacionados a instância e escopo) 269 | 270 | ```javascript 271 | class Shape { 272 | constructor (id, x, y) { 273 | this.id = id; 274 | this.move(x, y); 275 | } 276 | move (x, y) { 277 | this.x = x; 278 | this.y = y; 279 | } 280 | } 281 | 282 | let s = new Shape(1,0,0); 283 | s.move(3,3); 284 | // Shape {id: 1, x: 3, y: 3} 285 | ``` 286 | 287 | - o **this** é conhecido de quem já viu java. É o mesmo que o **self** da turma do **Python** 288 | - o **new** é o operador de instanciação. Ele chama o contrutor da classe 289 | 290 | ```javascript 291 | class Rectangle extends Shape { 292 | constructor (id, x, y, width, height) { 293 | super(id, x, y) 294 | this.width = width 295 | this.height = height 296 | } 297 | } 298 | class Circle extends Shape { 299 | constructor (id, x, y, radius) { 300 | super(id, x, y) 301 | this.radius = radius 302 | } 303 | } 304 | 305 | let r = new Rectangle(2,0,0,5,5); 306 | let c = new Circle(3,0,0,6); 307 | console.log(r instanceof Shape); 308 | console.log(c instanceof Shape); 309 | console.log(r instanceof Rectangle); 310 | console.log(c instanceof Circle); 311 | console.log(c instanceof Rectangle); 312 | // true, true, true, true, false 313 | ``` 314 | 315 | - herança de características 316 | - você pode acessar os comportamentos da classe ancestral utilizando o **[super](http://es6-features.org/#BaseClassAccess)** 317 | - note a tipagem. Às vezes é útil! 318 | - apenas reforçando, o **this** aponta para a **instância**! 319 | - tenho 4 retângulos, cada um tem um this, cada um tem um estado distinto um do outro 320 | 321 | ## FikDik 322 | Utilizar `const` para tudo, exceto nos casos em que a variável **deverá** receber um outro ponteiro/valor :v: 323 | 324 | ```javascript 325 | // TypeError: Assignment to constant variable. 326 | for (const i = 0; i < 10; i++) { 327 | console.log(i) 328 | } 329 | // Ok 330 | for (let i = 0; i < 10; i++) { 331 | console.log(i) 332 | } 333 | ``` 334 | 335 | Atenção para objetos 336 | 337 | ```javascript 338 | const obj = { 339 | name:'uri', 340 | age:90 341 | } 342 | 343 | obj.name = 'Yuri' 344 | obj.age = 18 345 | // works fine 346 | 347 | obj = { 348 | name:'IFCE', 349 | age:180 350 | } 351 | // you disgrace your house 352 | ``` 353 | 354 | - Que funcionalidades posso usar? http://node.green/ 355 | 356 | # Express 357 | 358 | `npm i express --save` 359 | 360 | Viu as dependências resolvidas e baixadas? :wink: 361 | 362 | ```javascript 363 | const express = require('express') 364 | const app = express() 365 | 366 | app.get('/', (req, res) => { 367 | res.send('Hello World!') 368 | }) 369 | 370 | app.listen(3000, _ => console.log('Example app listening on port 3000!')) 371 | ``` 372 | 373 | # Axios 374 | 375 | `npm i axios --save` 376 | 377 | ```javascript 378 | const axios = require("axios") 379 | 380 | const api = axios.create({ 381 | baseURL: "https://api.github.com" 382 | }) 383 | 384 | api.get("/search/users?q=sombriks").then(ret => console.log(ret.data)) 385 | ``` 386 | 387 | # Desafio :fire: 388 | 389 | Consultar a [API v3](https://developer.github.com/v3/) do GitHub para verificar quem comentou na issue [S03E02T02](https://github.com/seita-ifce/hello-js-v3/issues/11) publicando um link do repositório `hellojs-s03e02` até o dia `2017-10-13` 390 | 391 | **Prazo**: 2017-10-13 392 | -------------------------------------------------------------------------------- /S03E03.md: -------------------------------------------------------------------------------- 1 | # HelloJS 3.0.0 chapter 3 2 | 3 | - comecem criando o repositório porque a estrada é longa e o caminho é tudo, menos deserto! 4 | 5 | # Criando tabelas no SGBD 6 | 7 | ## Definição 8 | 9 | - [SQL](https://pt.wikipedia.org/wiki/SQL) 10 | - linguagem voltada para modelagem e consulta de dados 11 | - dados organizados em tabelas 12 | 13 | ## Aplicação 14 | 15 | ```sql 16 | -- contatoagenda.sql 17 | create table contatoagenda( 18 | idcontato integer not null primary key, 19 | nomecontato varchar(255) not null, 20 | telefonecontato varchar(255) not null 21 | ); 22 | ``` 23 | 24 | - o que este código significa? 25 | - na minha agenda terei contatos e deles guardarei nome, telefone e um identificador único 26 | - definições de tabelas contém listas de colunas (idcontato, nomecontato, telefonecontato) 27 | - colunas tem [tipo](https://www.sqlite.org/datatype3.html) (integer, varchar, date) 28 | - colunas tem modificadores (not null, primary key) 29 | - tipos podem ter tamanho (varchar(255)) 30 | - mas como é que roda esse código? 31 | 32 | ### SGBD: Sistema Gerenciador de Banco de Dados 33 | 34 | - o banco de dados quase sempre conta com uma ferramenta de administração 35 | - para [sqlite](http://sqlite.org/index.html) você pode usar o [dbbrowser](http://sqlitebrowser.org/) 36 | - usando o postgresql você pode usar o pgadmin ou a ferramenta de linha de comando, o psql 37 | - usando mysql tem o mysqladmin ou a ferramenta de linha de comando 38 | - usando oracle você tem... você pegou o espírito 39 | 40 | ## Exemplo 41 | 42 | - vamos criar a tabela usando sqlite 43 | - procure no computador um programa chamado db browser 44 | 45 | ### Rodando o exemplo dado no db browser 46 | 47 | - abra o db browser 48 | - aperte o botão "novo banco de dados" 49 | - salve o banco como **hello.sqlite** dentro da pasta do projeto **hellojs-s03e03** 50 | - se você não deu checkout no projeto, *do it now* 51 | - selecione a aba "executar SQL" 52 | - copie e cole o código ali 53 | - dê CTRL+enter ou aperte o botão de execução 54 | - volte para a aba estrutura do banco de dados e veja sua primeira tabela 55 | 56 | ### Outros SGBD's 57 | 58 | - demais ferramentas funcionam de modo parecido 59 | - definir as tabelas, entretanto, é apenas a primeira parte do processo 60 | 61 | # Revisão SQL 62 | 63 | ## Definição 64 | 65 | - não dá tempo, vamos adiante 66 | - lembre-se de salvar no seu git os exemplos de código! 67 | 68 | ## Aplicação 69 | 70 | - SQL serve pra salvar os dados de tal modo que extrair **informação** seja tarefa praticável 71 | 72 | ## Exemplo 73 | 74 | ### Create table 75 | 76 | ```sql 77 | -- evento.sql 78 | create table evento( 79 | idevento integer not null primary key, 80 | dscevento varchar(255) not null, 81 | dataevento date not null 82 | ); 83 | ``` 84 | 85 | - uma tabela tem relação com o mundo real 86 | - colunas tem relação com características de alguém, algum lugar, algum objeto, *conexão* etc 87 | - doravante chamados de *entidade* 88 | - se **eu** quisesse representar um cachorro em uma tabela: 89 | 90 | ```sql 91 | -- cachorro.sql 92 | create table cachorro( 93 | idcachorro integer not null primary key, 94 | nomecachorro varchar(255) not null, 95 | racacachorro varchar(255) 96 | ); 97 | ``` 98 | 99 | - note que **você** pode representar um cachorro de um modo diferente 100 | - evite acentuações ao definir colunas e tabelas. para o seu próprio bem 101 | 102 | ### Alter table 103 | 104 | - nosso modelo de dados nem sempre sai perfeito de primeira 105 | - o tempo passa e as coisas mudam 106 | - seu [esquema de dados](https://pt.wikipedia.org/wiki/Esquema_de_banco_de_dados) deve refletir o mundo em seu estado atual 107 | - se eu quiser adicionar a data de nascimento do cachorro: 108 | 109 | ```sql 110 | -- cachorro-2.sql 111 | alter table cachorro add column dtnascimentocachorro date; 112 | ``` 113 | 114 | - o alter table pode remover uma coluna e também mudar a definição de uma coluna 115 | - o sqlite [não faz](http://stackoverflow.com/questions/5938048/delete-column-from-sqlite-table/5987838#5987838) isso, mas o postgresql [faz](https://www.postgresql.org/docs/9.6/static/sql-altertable.html) 116 | 117 | ### Drop table 118 | 119 | - remover do seu esquema de dados uma entidade ou relacionamento 120 | 121 | ```sql 122 | -- cachorro-3.sql 123 | drop table cachorro; 124 | ``` 125 | 126 | ### Insert 127 | 128 | - sabemos manipular as tabelas, agora vamos inserir dados nelas 129 | 130 | ```sql 131 | -- contatoagenda-2.sql 132 | insert into contatoagenda (nomecontato,telefonecontato) values ('Jane','123454321'); 133 | insert into contatoagenda (nomecontato,telefonecontato) values ('José','987654321'); 134 | insert into contatoagenda (nomecontato,telefonecontato) values ('Fran','543212345'); 135 | insert into contatoagenda (nomecontato,telefonecontato) values ('João','123456789'); 136 | insert into evento(dscevento,dataevento) values ('Jantar fim de semana', '2016-11-19'); 137 | insert into evento(dscevento,dataevento) values ('Pegar uma praia', '2016-11-20'); 138 | insert into evento(dscevento,dataevento) values ('Natal', '2016-12-25'); 139 | ``` 140 | 141 | - não precisamos indicar um valor para a cioluna **idcontato** 142 | - o valor da chave é gerenciado pelo SGBD 9 de 10 vezes 143 | - datas podem ser representadas como texto. Meio doido, eu sei 144 | - atenção para não inserir dados duplicados no banco! 145 | 146 | ### Update 147 | 148 | - usamos quando queremos fazer ajustes em algum dado de alguma tabela 149 | 150 | ```sql 151 | -- exemplo-update.sql 152 | update contatoagenda set telefonecontato = '121232121' where idcontato = 1; 153 | update evento set dscevento = 'subir a serra' where dataevento = '2016-11-19'; 154 | ``` 155 | 156 | - **cuidado com o update sem where!!!** 157 | - se não tem condição, o SQL entende que é pra aplicar em todo mundo da tabela 158 | 159 | ### Delete 160 | 161 | - usamos quando queremos remover dados de uma tabela 162 | 163 | ```sql 164 | -- exemplo-delete.sql 165 | delete from contatoagenda where nomecontato = 'João'; 166 | ``` 167 | 168 | - **cuidado com o delete sem where!!!** 169 | 170 | ## Select 171 | 172 | - usamos quando desejamos consultar (sem ser pela interface gráfica do db browser) os dados de uma tabela 173 | - é onde os **dados** podem virar **informação** 174 | - é onde a magia negra reside 175 | - vide exercícios de aprofundamento 176 | 177 | ```sql 178 | -- exemplo-select.sql 179 | select * from contatoagenda; 180 | ``` 181 | 182 | - devolve todo mundo 183 | 184 | ```sql 185 | -- exemplo-select-2.sql 186 | select * from contatoagenda where nomecontato = 'Fran'; 187 | ``` 188 | 189 | - devolve só quem se chama Fran 190 | 191 | ```sql 192 | -- exemplo-select-3.sql 193 | select * from contatoagenda where idcontato = 3; 194 | ``` 195 | 196 | - devolve quem tem o id valendo 3 197 | 198 | ```sql 199 | -- exemplo-select-4.sql 200 | select * from contatoagenda, evento; 201 | ``` 202 | 203 | - consultas podem consultar mais de uma tabela ao mesmo tempo 204 | - sem um critério, o SQL realiza um cruzamento cartesiano dos dados. 205 | 206 | ```sql 207 | -- exemplo-select-5.sql 208 | create table participantesevento( 209 | idcontato integer not null, 210 | idevento integer not null, 211 | foreign key (idcontato) references contatoagenda(idcontato), 212 | foreign key (idevento) references evento(idevento), 213 | primary key (idcontato,idevento) 214 | ); 215 | 216 | insert into participantesevento (idcontato,idevento) values (1,1); 217 | insert into participantesevento (idcontato,idevento) values (2,1); 218 | insert into participantesevento (idcontato,idevento) values (1,3); 219 | insert into participantesevento (idcontato,idevento) values (1,2); 220 | insert into participantesevento (idcontato,idevento) values (2,3); 221 | insert into participantesevento (idcontato,idevento) values (3,3); 222 | 223 | select 224 | * 225 | from 226 | contatoagenda, evento, participantesevento 227 | where 228 | contatoagenda.idcontato = participantesevento.idcontato 229 | and evento.idevento = participantesevento.idevento 230 | and participantesevento.idevento = 3 231 | ``` 232 | 233 | - a tabela **participantesevento** faz uso do que chamamos de **chave estrangeira** 234 | - os dados inseridos nela são chaves de outras tabelas. é bom que estas chaves existam 235 | - na consulta exemplificada a where apresentada garante que as chaves condizem umas com as outras 236 | - assim evitamos o cartesiano e extraímos a informação desejada: saber quem vai participar do evento 3 (natal) 237 | 238 | # Introdução ao knex.js 239 | 240 | ## Definição 241 | 242 | - biblioteca node 243 | - depende do npm para instalar 244 | - [query builder](http://knexjs.org/) 245 | - ajuda na consulta em bancos de dados 246 | - compatível com mysql, postgresql, oracle, e sqlite3 247 | - entender um query builder ajudará a entender melhor um ORM 248 | 249 | ## Aplicação 250 | 251 | - aplicativos que usem bases relacionais para salvar dados 252 | - atrelar interfaces a uma modelagem de negócio 253 | - facilitar na hora de manter o código compatível com bancos distintos 254 | 255 | ## Exemplo 256 | 257 | - passo inicial configurar um projeto via terminal 258 | - crie este projeto na pasta do repositório da aula 4 259 | 260 | ```bash 261 | mkdir intro-knex 262 | cd intro-knex 263 | npm init . 264 | ``` 265 | 266 | - o [npm](https://www.npmjs.com/) (Node Package Manager) gerencia projetos nodejs 267 | - node por si só já tem módulos úteis 268 | - o npm fornece mais de [200 mil pacotes](https://en.wikipedia.org/wiki/Npm_(software)#cite_note-KennedyDevay16-7) 269 | - normalemte vem junto quando você instala o node 270 | - o comando **"npm init ."** começa uma sessão de perguntas sobre o projeto sendo criado 271 | - ao final das perguntas, a pasta do projeto terá um arquivo chamado **package.json** 272 | 273 | ```bash 274 | npm install knex -g 275 | npm install knex --save 276 | npm install sqlite3 --save 277 | ``` 278 | 279 | - instalar dependências num projeto npm é só isso aí 280 | - a parte do **"--save"** é pra salvar os pacotes no **package.json**, na seção de dependências 281 | - abra e veja como o seu **package.json** está 282 | - ao instalar pacotes a pasta **node_modules** é criada também 283 | - a boa etiqueta diz: jamais subirá para o controle de versão a **node_modules** 284 | - você pode ignorá-la usando o arquivo **.gitignore** 285 | 286 | # Inserir, remover e atualizar dados no banco 287 | 288 | ## Definição 289 | 290 | - as operações básicas do SQL vistas na Aula 3 podem ser executadas por um javascript 291 | - em vez de alimentarmos diretamente nossa base de dados, façamos um ou vários programas para cumprirem esta missão 292 | 293 | ## Aplicação 294 | 295 | - seu programa alimenta uma base de dados que lhe permitirá criar consultas complexas no futuro 296 | - seu programa pode otimizar determinadas tarefas de coleta de dados 297 | 298 | ## Exemplo 299 | 300 | ```javascript 301 | // hello-knex-1.js 302 | const knex = require("knex")({ 303 | client: "sqlite3", 304 | connection: { 305 | filename: "./hello.sqlite" 306 | }, 307 | useNullAsDefault: true // coisas de sqlite.. ¯\_(ツ)_/¯ 308 | }); 309 | 310 | // criar uma tabela 311 | knex.schema.createTable("convidado", (table) =>{ 312 | table.increments("idconvidado"); 313 | table.string("nomeconvidado"); 314 | }).then(() => { 315 | console.log("tabela criada"); 316 | process.exit(0); 317 | }).catch((err)=>{ 318 | console.log(err); 319 | process.exit(1); 320 | }); 321 | ``` 322 | 323 | - primeiro definimos os parâmetros de conexão na criação do query builder 324 | - nosso banco é um sqlite e o arquivo de banco se chama *hello.sqlite* 325 | - depois usamos o query builder pra criar uma tabela chamada *convidado* 326 | - a tabela tem duas colunas: *idconvidado* e *nomecovidado* 327 | - o knex também é de natureza assíncrona, mas usa [promessas em vez de callbacks](http://bluebirdjs.com/docs/why-promises.html) 328 | - esse javascript manipula sql. ele herda certas características vistas no sql 329 | - rodar uma segunda vez dá erro, por exemplo 330 | 331 | ```javascript 332 | // hello-knex-2.js 333 | const knex = require("knex")({ 334 | client: "sqlite3", 335 | connection: { 336 | filename: "./hello.sqlite" 337 | }, 338 | useNullAsDefault: true // ¯\_(ツ)_/¯ 339 | }); 340 | 341 | // queremos um nome para este convidado 342 | if(!process.argv[2]){ 343 | console.log("usage: node hello-knex-2.js "); 344 | process.exit(0); 345 | } 346 | 347 | // inserir convidados 348 | knex("convidado").insert({ 349 | nomeconvidado:process.argv[2] 350 | },"idconvidado").then((ret) => { 351 | console.log(`convidado inserido com a chave ${ret[0]}`); 352 | process.exit(0); 353 | }).catch((err)=>{ 354 | console.log(err); 355 | process.exit(1); 356 | }); 357 | ``` 358 | 359 | - o código lembra mais javascript do que sql 360 | - você pode conferir seus dados com o **db browser** (*sqlite-browser*) visto na aula 3 361 | - aquela parte de configurar o banco é sempre igual 362 | 363 | ```javascript 364 | // db.js 365 | const knex = require("knex")({ 366 | client: "sqlite3", 367 | connection: { 368 | filename: "./hello.sqlite" 369 | }, 370 | useNullAsDefault: true // ¯\_(ツ)_/¯ 371 | }); 372 | module.exports = knex; 373 | ``` 374 | 375 | - nos demais exemplos faremos require no arquivo **db.js** 376 | - **require("./db")** 377 | 378 | ```javascript 379 | // hello-knex-3.js 380 | "use strict" 381 | const knex = require("./db"); 382 | 383 | if(!process.argv[3]){ 384 | console.log("usage: node hello-knex-3.js "); 385 | process.exit(0); 386 | } 387 | 388 | let id = process.argv[2]; 389 | let nome = process.argv[3]; 390 | 391 | // atualizar convidados 392 | knex("convidado").update({ 393 | nomeconvidado:nome 394 | }).where({ 395 | idconvidado:id 396 | }).then((ret) => { 397 | console.log(`convidado ${id} renomeado para ${nome}`); 398 | process.exit(0); 399 | }).catch(function(err){ // caso você goste mais desta sintaxe 400 | console.log(err); 401 | process.exit(1); 402 | }); 403 | ``` 404 | 405 | - o knex tenta preservar a ideia original dos verbos do SQL 406 | - a [documentação oficial](http://knexjs.org/) tem exemplos caso a caso 407 | - [outros tutoriais](https://github.com/sombriks/sample-knex-cookbook) tem uma tentativa de sequencia 408 | 409 | ```javascript 410 | // hello-knex-4.js 411 | "use strict" 412 | const knex = require("./db"); 413 | 414 | if(!process.argv[2]){ 415 | console.log("usage: node hello-knex-4.js "); 416 | process.exit(0); 417 | } 418 | 419 | let id = process.argv[2]; 420 | 421 | // atualizar convidados 422 | knex("convidado").del().where({ 423 | idconvidado:id 424 | }).then(() => { 425 | console.log(`convidado ${id} removido`); 426 | process.exit(0); 427 | }).catch((err) => { 428 | console.log(err); 429 | process.exit(1); 430 | }); 431 | ``` 432 | 433 | - ao mudarmos, por exemplo, o sgbd de sqlite para postgresql, só o arquivo db.js necessitaria de mudança 434 | - os demais scripts fazem uso da API do query builder em vez de usar o dialeto SQL do sqlite diretamente 435 | 436 | # Consultando o banco de dados via knex.js 437 | 438 | ## Definição 439 | 440 | - assim como insert, update e delete, o select também tem suporte no builder 441 | 442 | ## Aplicação 443 | 444 | - recuperar os dados do banco de dados. claro. 445 | 446 | ## Exemplo 447 | 448 | ```javascript 449 | // hello-knex-5.js 450 | "use strict" 451 | const knex = require("./db"); 452 | 453 | knex("convidado").select().then(function(ret){ 454 | console.log("id\t\tnome") 455 | let i = ret.length; 456 | while(i--){ 457 | let conv = ret[i]; 458 | console.log(`${conv.idconvidado}\t\t${conv.nomeconvidado}`); 459 | } 460 | process.exit(0); 461 | }); 462 | ``` 463 | 464 | - **knex("convidado").select()** equivale a **select * from convidado** 465 | 466 | ```javascript 467 | // hello-knex-6.js 468 | "use strict" 469 | const knex = require("./db"); 470 | 471 | if(!process.argv[2]){ 472 | console.log("usage: node hello-knex-6.js "); 473 | process.exit(0); 474 | } 475 | 476 | knex("convidado").select().where({ 477 | idconvidado:process.argv[2] 478 | }).then(function(ret){ 479 | console.log("id\t\tnome") 480 | let i = ret.length; 481 | while(i--){ 482 | let conv = ret[i]; 483 | console.log(conv); 484 | // console.log(Object.values(conv)); 485 | // console.log(Object.keys(conv).map(key => conv[key])); 486 | } 487 | process.exit(0); 488 | }); 489 | ``` 490 | 491 | - a where do builder tem [vários outros idiomas possíveis](http://knexjs.org/#Builder-wheres) 492 | - podemos encadear wheres 493 | - podemos passar subconsultas para as wheres 494 | - o builder suporta algumas sintaxes alternativas 495 | 496 | ```javascript 497 | // hello-knex-7.js 498 | const knex = require("./db"); 499 | 500 | if(!process.argv[3]){ 501 | console.log("usage: node hello-knex-7.js "); 502 | process.exit(0); 503 | } 504 | 505 | let q = "update convidado set nomeconvidado = :nome where idconvidado = :id"; 506 | let p = { 507 | nome: process.argv[3], 508 | id: process.argv[2] 509 | }; 510 | 511 | knex.raw(q,p).then(() => { 512 | // você pode encadear consultas assim 513 | knex.raw("select * from convidado").then((ret) => { 514 | let i = ret.length; 515 | while(i--){ 516 | console.log(ret[i]); 517 | } 518 | process.exit(0); 519 | }); 520 | }); 521 | ``` 522 | 523 | - caso o builder de modo algum lhe agrade, existe ainda a opção de usar SQL diretamente 524 | - atenção para o dialeto SQL do sgbd 525 | - sempre use variáveis nomeadas, jamais concatene SQL (evite o [bobby tables](https://xkcd.com/327/)) 526 | - no modo raw, o ret tem o atributo **rows** 527 | 528 | # Introdução a migrações de banco de dados com knex 529 | 530 | ## Definição 531 | 532 | - esquema é uma forma de organizar o banco de maneira lógica 533 | - essa organização ~~pode~~ vai mudar. colunas deixarão de existir e outras serão criadas 534 | - como manter os esquemas organizados? 535 | - ~~tinder~~ **migrações** de esquemas :bowtie: 536 | 537 | ## Aplicação 538 | 539 | - alterando tabelas 540 | - mudando de ideia 541 | 542 | ## Exemplo 543 | 544 | - criar tabela cachorro (aula 3) 545 | 546 | com SQL: 547 | 548 | ```javascript 549 | create table cachorro( 550 | idcachorro integer not null primary key, 551 | nomecachorro varchar(255) not null, 552 | racacachorro varchar(255) 553 | ); 554 | ``` 555 | 556 | com knex: 557 | 558 | ```bash 559 | $ knex init 560 | $ knex migrate:make cachorro_inicial 561 | ``` 562 | 563 | `$ knex init` cria um arquivo `knexfile.js`, que nada mais é do que o nosso conhecido `db.js` *on steroids* 564 | 565 | ```bash 566 | . 567 | ├── db.js 568 | ├── hallo-knex-1.js 569 | ├── hallo-knex-2.js 570 | ├── hallo-knex-3.js 571 | ├── hallo-knex-4.js 572 | ├── hallo-knex-5.js 573 | ├── hallo-knex-6.js 574 | ├── hallo-knex-7.js 575 | ├── hello.sqlite 576 | ├── knexfile.js 577 | ├── migrations 578 | │ └── 20161122232554_cachorro_inicial.js 579 | ├── node_modules 580 | │ ├── knex 581 | │ └── sqlite3 582 | └── package.json 583 | ``` 584 | 585 | a pasta **migrations** é onde a magia acontece 586 | 587 | ```javascript 588 | // 20161122232554_cachorro_inicial.js 589 | exports.up = function(knex, Promise) { 590 | return knex.schema.createTableIfNotExists("cachorro", (table) => { 591 | table.increments("idcachorro"); 592 | table.string("nomecachorro"); 593 | }); 594 | }; 595 | 596 | exports.down = function(knex, Promise) { 597 | return knex.schema.dropTableIfExists("cachorro"); 598 | }; 599 | ``` 600 | 601 | `$ knex migrate:latest` -- subindo.. 602 | 603 | ```bash 604 | . 605 | ├── db.js 606 | ├── dev.sqlite3 607 | ... 608 | ``` 609 | 610 | iniciando o banco com tótó: 611 | 612 | ```javascript 613 | // hello-knex-8.js 614 | const knexfile = require('./knexfile')["development"]; 615 | const knex = require("knex")(knexfile); // olha a macumba.. 616 | 617 | // queremos um nome para este cachorro 618 | if(!process.argv[2]){ 619 | console.log("usage: node hello-knex-8.js "); 620 | process.exit(0); 621 | } 622 | 623 | // inserir cachorro 624 | knex("cachorro").insert({ 625 | nomecachorro:process.argv[2] 626 | },"idcachorro").then((ret) => { 627 | console.log(`cachorro inserido com a chave ${ret[0]}`); 628 | process.exit(0); 629 | }).catch((err)=>{ 630 | console.log(err); 631 | process.exit(1); 632 | }); 633 | ``` 634 | 635 | ops! esquecemos de escolher a marca do cachorro: 636 | 637 | `$ knex migrate:make adiciona_marca_cachorro` 638 | 639 | ```javascript 640 | // 20161123000421_adiciona_marca_cachorro.js 641 | exports.up = function(knex, Promise) { 642 | return knex.schema.table("cachorro", (table) => { 643 | table.string("marcacachorro"); 644 | }); 645 | }; 646 | 647 | exports.down = function(knex, Promise) { 648 | return knex.schema.table("cachorro", (table) => table.dropColumn("marcacachorro")); 649 | }; 650 | ``` 651 | 652 | `$ knex migrate:latest` 653 | 654 | agora nosso tótó tem marca 655 | 656 | mudou de ideia? *rollback, babe* 657 | 658 | `$ knex migrate:rollback` desfaz o último migrate que fizemos 659 | 660 | # Exercício / desafio 661 | 662 | - crie no github um repositório chamado **hellojs-s03e03** 663 | - faça checkout dele na máquina local (consulte aulas passadas ou o universo caso necessite lembrar como é isso) 664 | - crie o projeto npm na cópia local deste repositório 665 | - salve o knex e o sqlite3 como dependências de projeto 666 | 667 | - crie um arquivo chamado **.gitignore** e escreva nele **node_modules** 668 | - pronto seu comit não versionará a node modules 669 | - comite o que fizemos até agora para o git 670 | 671 | - crie uma tabela chamada evento 672 | - dos eventos desejaremos saber 673 | - descrição do evento 674 | - data de início do evento 675 | - baseie-se no código fornecido 676 | - crie uma coluna chamada idevento para ser a chave primária da tabela evento 677 | 678 | - a parte de consultas fica maior e mais interessante que isso. 679 | - a tarefa é criar mais um arquivo de exemplo de sql e testá-lo no sqlite/db browser 680 | - esta consulta deverá fazer uso das funções explicadas [aqui](https://sqlite.org/lang_aggfunc.html#count) 681 | - uma consulta que diga quantos participantes cada evento terá 682 | 683 | - altere os scripts **hello-knex-1.js** e **hello-knex-2.js** para fazerem uso do **db.js** 684 | - comite suas alterações para o github 685 | 686 | - crie um insert usando *knex.raw* e chame de hello-knex-8.js 687 | - você deve receber o nome que deseja incluir 688 | 689 | - criem: 690 | - um migrate com a tabela cachorro 691 | - um migrate inserindo 2 cachorros 692 | - um migrate adicionando a coluna marcacachorro à tabela 693 | - tentem fazer *rollback* e mudem de ideia de novo 694 | - um arquivo a ser executado `$ node meuscachorros.js` que recebe o nome e a marca do cão e insere o cachorro na tabela 695 | - um arquivo a ser executado `$ node cademeucatiorro.js` que busca um cachorro pelo nome 696 | - um migrate com a tabela `presenca` contendo as colunas `usuario`, `episodio`, `datapresenca`, `repo` 697 | 698 | - crie um insert usando *knex.raw* inserindo um aluno Teste e chame de hello-presenca.js 699 | 700 | ## Top-top challenge :space_invader: 701 | 702 | Utilize a solução do ep `S03e02` para realizar inserts na tabela `presenca`. 703 | 704 | ### Qual o objetivo? 705 | 706 | Ter na tabela `presenca` todos os participantes que postaram links de repositórios com as implementações até as datas limites. 707 | 708 | ### Dúvidas? 709 | 710 | - Prazo para entrega (e postagem do link do repositório na issue [S03E03](/issues/3) : 2017-09-18) 711 | -------------------------------------------------------------------------------- /S03E04.md: -------------------------------------------------------------------------------- 1 | # HelloJS 3.0.0 chapter 4 2 | 3 | - respondam a issue de chamada 4 | - criem o repositório de hoje na conta de vocês 5 | - hellojs-s03e04 6 | - atenção para os caminhos de pedra de hoje 7 | 8 | ## Agenda 9 | 10 | - knex 11 | - knex migrations 12 | - um pouco mais sobre o express 13 | - servindo arquivos estáticos 14 | - formulário html 15 | - javascript client side 16 | 17 | ## knex 18 | 19 | ```bash 20 | 21 | mkdir hellojs-s03e04 22 | # ou git clone https://github.com//hellojs-s03e04.git 23 | 24 | cd hellojs-s03e04 25 | npm init . -y 26 | 27 | # agora nossas dependências 28 | npm install express sqlite3 knex --save 29 | 30 | # caso você tenha o root da máquina 31 | sudo npm -g install knex 32 | ``` 33 | 34 | - use o sqlitebrowser pra criar um banco de dados chamado **s03e04.sqlite3** dentro da pasta do projeto 35 | 36 | ```sql 37 | create table pessoa( 38 | idpessoa integer not null primary key autoincrement, 39 | nomepessoa varchar(255) not null, 40 | cpfpessoa varchar(255) unique not null, 41 | emailpessoa varchar(255) unique 42 | ); 43 | ``` 44 | 45 | - salve umas 3 ou 4 pessoas. seja criativo. 46 | - usando os super poderes do knex, crie um arquivo de configuração 47 | 48 | ```bash 49 | knex init . 50 | ``` 51 | 52 | - o arquivo **knexfile.js** deverá surgir 53 | - caso o comando acima não funcione (porque a máquina está sem knex global): 54 | 55 | ```bash 56 | ./node_modules/.bin/knex init . 57 | # magia! 58 | ``` 59 | 60 | - o **knexfile.js** serve de base e de exemplo para você criar perfis de conexão 61 | - segue exemplo de **knexfile.js** 62 | 63 | ```javascript 64 | // Update with your config settings. 65 | 66 | module.exports = { 67 | 68 | development: { 69 | client: 'sqlite3', 70 | connection: { 71 | filename: './s03e04.sqlite3' 72 | } 73 | }, 74 | 75 | // outras linhas que não nos interessam agora 76 | }; 77 | ``` 78 | 79 | - abra o seu knexfile e mude **dev.sqlite3** para **s03e04.sqlite3** 80 | - crie o db.js, onde vamos configurar o acesso ao banco: 81 | 82 | ```javascript 83 | // db.js 84 | const cfg = require("./knexfile").development 85 | const knex = require("knex")(cfg) 86 | exports.knex = knex 87 | ``` 88 | 89 | - crie o **index.js**, que será o entry point do node 90 | 91 | ```javascript 92 | // index.js 93 | const knex = require("./db").knex 94 | const express = require("express") 95 | const app = express() 96 | 97 | app.get("/pessoas/list", (req, res) => { 98 | knex("pessoas").select().then(ret => { 99 | res.send(ret) 100 | }).catch(err => { 101 | console.log(err) 102 | res.status(500).send(err) 103 | }) 104 | }) 105 | 106 | app.listen(3000, _ => console.log('All subsystems - [ONLINE]')) 107 | 108 | // ja ja mexemos nisso 109 | ``` 110 | 111 | - execute o script 112 | 113 | ```bash 114 | node index.js 115 | ``` 116 | 117 | - visite no browser http://127.0.0.1:3000/pessoas/list 118 | - veja se você identifica as pessoas que você criou 119 | - dê ctrl+c no console para matar o node 120 | 121 | ## knex migrations 122 | 123 | - desenvolvedor não deve ter medo de mexer no banco 124 | - o esquema de dados evolui que nem todo o resto 125 | - [migrações de esquema](https://en.wikipedia.org/wiki/Schema_migration) ao resgate! 126 | - criar nosso primeiro esquema 127 | 128 | ```bash 129 | knex migrate:make esquema_inicial 130 | # ./node_modules/.bin/knex migrate:make esquema_inicial 131 | # deve aparecer uma pasta chamada migrations e dentro dela um arquivo nomeado mais ou menos assim: 20170919140032_esquema_inicial.js 132 | ``` 133 | 134 | - usando os poderes do knex documentados [aqui](http://knexjs.org/), vamos criar a tabela de eventos: 135 | 136 | ```javascript 137 | // 20170919140032_esquema_inicial.js 138 | exports.up = knex => knex.schema.createTable("evento", tb => { 139 | tb.increments("idevento") 140 | tb.string("tituloevento").notNullable() 141 | tb.timestamp("dthoraevento").defaultTo(knex.fn.now()) 142 | }) 143 | 144 | exports.down = knex => knex.schema.dropTable("evento") 145 | ``` 146 | 147 | - você deve "subir" o migrate para o seu esquema de dados: 148 | 149 | ```bash 150 | knex migrate:latest 151 | ``` 152 | 153 | - use o [dbbrowser](http://sqlitebrowser.org/) pra ver se a tabela nova foi criada 154 | - em tempo de desenvolvimento você pode detectar algum erro e pode voltar a base para poder corrigir: 155 | 156 | ```bash 157 | knex migrate:rollback 158 | # ps: não faz sentido rollback de migrate em produção. 159 | ``` 160 | 161 | - é de responsabilidade do seu aplicativo verificar se o esquema está na versão mais recente. 162 | - altere o **index.js**: 163 | 164 | ```javascript 165 | // index.js 166 | const knex = require("./db").knex 167 | const express = require("express") 168 | const app = express() 169 | 170 | app.get("/pessoas/list", (req, res) => { 171 | knex("pessoas").select().then(ret => { 172 | res.send(ret) 173 | }).catch(err => { 174 | console.log(err) 175 | res.status(500).send(err) 176 | }) 177 | }) 178 | 179 | knex.migrate.latest().then(_=>{ 180 | console.log("knex migrate latest") 181 | app.listen(3000, _ => console.log('All subsystems - [ONLINE]')) 182 | }) 183 | 184 | // ja ja mexemos mais nisso 185 | ``` 186 | 187 | - podemos usar o express para servir conteúdo estático também 188 | - não é obrigatório só servir código 189 | - crie uma pasta chamada *public* 190 | 191 | ```bash 192 | mkdir public 193 | ``` 194 | 195 | - altere o index.js mais uma vez 196 | 197 | ```javascript 198 | // index.js 199 | const knex = require("./db").knex 200 | const express = require("express") 201 | const app = express() 202 | 203 | app.use(express.static("public")) 204 | 205 | app.get("/pessoas/list", (req, res) => { 206 | knex("pessoa").select().then(ret => { 207 | res.send(ret) 208 | }).catch(err => { 209 | console.log(err) 210 | res.status(500).send(err) 211 | }) 212 | }) 213 | 214 | knex.migrate.latest().then(_=>{ 215 | console.log("knex migrate latest") 216 | app.listen(3000, _ => console.log('All subsystems - [ONLINE]')) 217 | }) 218 | 219 | // ja ja mexemos mais nisso 220 | ``` 221 | 222 | ## arquivos estáticos via express 223 | 224 | - dentro da pasta **public**, crie um arquivo chamado **ola.txt** 225 | 226 | ```bash 227 | echo "hello, js!" > public/ola.txt 228 | # echo "hello, js!" > public\ola.txt se for windows 229 | ``` 230 | 231 | - execute **node index.js** novamente 232 | - visite http://127.0.0.1:3000/ola.txt 233 | - por que servir arquivos estáticos? 234 | - podemos servir páginas html 235 | - html, js, css, imagens, vídeos, músicas, etc, etc 236 | - documentação [aqui](http://expressjs.com/en/starter/static-files.html) 237 | 238 | ## arquivos HTML 239 | 240 | - Hyper Text Markup Language 241 | - versão 5 da linguagem 242 | - *marcou* pra sempre a forma de consumirmos a internet 243 | 244 | ```html 245 | 246 | 247 | 248 | Hello, JS! 249 | 250 | 251 |

Hello, JS!

252 |

Versão 3.0.0 do treinamento

253 | 254 | 255 | ``` 256 | 257 | - salve o exemplo acima dentro da public com o nome index.html 258 | - visite http://127.0.0.1:3000/index.html 259 | - tá, texto formatado, qual a graça? 260 | - formulários 261 | - links 262 | - much more! 263 | 264 | ```html 265 | 266 | 267 | 268 | 269 | Hello, JS! 270 | 271 | 272 |

Hello, JS!

273 |

Versão 3.0.0 do treinamento

274 | Voltar 275 |
276 |