Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# OS Files
.DS_Store
Thumbs.db

# Dependencies
node_modules/

# Dev/Build Artifacts
/dist/
/tests/e2e/videos/
/tests/e2e/screenshots/
/tests/unit/coverage/
jsconfig.json

# Local Env Files
.env.local
.env.*.local
.env

# Log Files
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Unconfigured Editors
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw*
16 changes: 16 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "vaga-backend-teste",
"version": "1.0.0",
"main": "src/server.js",
"repository": "https://github.com/jpsoaresXy/vaga-backend-teste.git",
"author": "Joao Pedro <[email protected]>",
"license": "MIT",
"dependencies": {
"cors": "^2.8.5",
"express": "^4.17.3",
"multer": "^1.4.4",
"mysql2": "^2.3.3",
"read-excel-file": "^5.2.28",
"sequelize": "^6.17.0"
}
}
Binary file not shown.
13 changes: 13 additions & 0 deletions src/config/db.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
HOST: "localhost",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia ter criado variáveis ambientes

USER: "root",
PASSWORD: "123456",
DB: "testdb",
dialect: "mysql",
pool: {
max: 1000,
min: 0,
acquire: 30000,
idle: 10000
}
};
85 changes: 85 additions & 0 deletions src/controllers/pokemon/excel.controllers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
const db = require("../../models");
const Pokemon = db.pokemons;
const readXlsxFile = require("read-excel-file/node");
const upload = async (req, res) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia criar uma classe controller para ficar mais organizado

try {
if (req.file == undefined) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não precisaria verificar já que o middleware faz isso

return res.status(400).send("Please upload an excel file!");
}
let path =
__basedir + "/resources/static/assets/uploads/" + req.file.filename;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia usar a lib fs pra pegar o caminho do diretório e facilitar essa busca

readXlsxFile(path).then((rows) => {
// skip header
rows.shift();
let pokemons = [];
rows.forEach((row) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aqui vc poderia usar o map, ele é mais rápido em termos de performance e já retorna um array pra você, não precisando criar um array de dar push.

let pokemon = {
id: row[0],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ao invés de pegar cada coluna da linha indicando o índice(row[0]) por exemplo, voce poderia desestruturar, assim:

const [id, name, pokedex_number, img_name, generation...] = row

name: row[1],
pokedex_number: row[2],
img_name: row[3],
generation: row[4],
evolution_stage: row[5],
evolved: row[6],
family_id: row[7],
cross_gen: row[8],
type_1: row[9],
type_2: row[10],
wether_1: row[11],
wether_2: row[12],
stat_total: row[13],
atk: row[14],
def: row[15],
sta: row[16],
legendary: row[17],
aquireable: row[18],
spawns: row[19],
regional: row[20],
raidable: row[21],
hatchable: row[22],
shiny: row[23],
nest: row[24],
new: row[25],
not_gettable: row[26],
future_evolve: row[27],
'100%_cp_@40': row[28],
'100%_cp_@39': row[29],
};
pokemons.push(pokemon);
});
Pokemon.bulkCreate(pokemons)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Se a função é assíncrona, poderia então usar o await ao invés do then e catch

.then(() => {
res.status(200).send({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

o status padrão pra criação de dados é o 201

message: "Uploaded the file successfully: " + req.file.originalname,
});
})
.catch((error) => {
res.status(500).send({
message: "Fail to import data into database!",
error: error.message,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

o stacktrace do erro fica perdido aqui.

});
});
});
} catch (error) {
console.log(error);
res.status(500).send({
message: "Could not upload the file: " + req.file.originalname,
});
}
};
const getPokemons = (req, res) => {
Pokemon.findAll()

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia deixar assíncrono e fazer assim:

return await Pokemon.findAll()

.then((data) => {
res.send(data);
})
.catch((err) => {
res.status(500).send({
message:
err.message || "Some error occurred while retrieving pokemons.",
});
});
};
module.exports = {
upload,
getPokemons,
};
22 changes: 22 additions & 0 deletions src/middlewares/upload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const multer = require("multer");
const excelFilter = (req, file, cb) => {
if (
file.mimetype.includes("excel") ||
file.mimetype.includes("spreadsheetml")
) {
cb(null, true);
} else {
cb("Please upload only excel file.", false);
}
};
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __basedir + "/resources/static/assets/uploads/");
},
filename: (req, file, cb) => {
/* console.log(file.originalname); */

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pode remover o comentario

cb(null, `${Date.now()}-bezkoder-${file.originalname}`);
},
});
var uploadFile = multer({ storage: storage, fileFilter: excelFilter });
module.exports = uploadFile;
18 changes: 18 additions & 0 deletions src/models/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const dbConfig = require("../config/db.config.js");
const Sequelize = require("sequelize");
const sequelize = new Sequelize(dbConfig.DB, dbConfig.USER, dbConfig.PASSWORD, {
host: dbConfig.HOST,
dialect: dbConfig.dialect,
operatorsAliases: false,
pool: {
max: dbConfig.pool.max,
min: dbConfig.pool.min,
acquire: dbConfig.pool.acquire,
idle: dbConfig.pool.idle
}
});
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.pokemons = require("./pokemon.model.js")(sequelize, Sequelize);
module.exports = db;
96 changes: 96 additions & 0 deletions src/models/pokemon.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
module.exports = (sequelize, Sequelize) => {
const Pokemon = sequelize.define("pokemon", {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nome da tabela é interessante colocar sempre no plural

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O plural de pokemon é pokemon 🤣

id : {
type: Sequelize.INTEGER,
primaryKey : true
},
name: {
type: Sequelize.STRING
},
pokedex_number: {
type: Sequelize.STRING,
},
img_name: {
type: Sequelize.STRING
},
generation: {
type: Sequelize.STRING
},
evolution_stage: {
type: Sequelize.STRING
},
evolved: {
type: Sequelize.STRING

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia converter os dados numéricos e booleano e salvar com o tipo certo no banco para ocupar menos espaço

},
family_id: {
type: Sequelize.STRING
},
cross_gen: {
type: Sequelize.STRING
},
type_1: {
type: Sequelize.STRING
},
type_2: {
type: Sequelize.STRING
},
wether_1: {
type: Sequelize.STRING
},
wether_2: {
type: Sequelize.STRING
},
stat_total: {
type: Sequelize.STRING
},
atk: {
type: Sequelize.STRING
},
def: {
type: Sequelize.STRING
},
sta: {
type: Sequelize.STRING
},
legendary: {
type: Sequelize.STRING
},
aquireable: {
type: Sequelize.STRING
},
spawns: {
type: Sequelize.STRING
},
regional: {
type: Sequelize.STRING
},
raidable: {
type: Sequelize.STRING
},
hatchable: {
type: Sequelize.STRING
},
shiny: {
type: Sequelize.STRING
},
nest: {
type: Sequelize.STRING
},
new: {
type: Sequelize.STRING
},
not_gettable: {
type: Sequelize.STRING
},
future_evolve: {
type: Sequelize.STRING
},
'100%_cp_@40': {
type: Sequelize.STRING
},
'100%_cp_@39': {
type: Sequelize.STRING
},
});
return Pokemon;
};
10 changes: 10 additions & 0 deletions src/routes/pokemon.routes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const express = require("express");
const router = express.Router();
const excelController = require("../controllers/pokemon/excel.controllers");
const upload = require("../middlewares/upload");
let routes = (app) => {
router.post("/upload", upload.single("file"), excelController.upload);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Poderia separar em duas rotas, uma para fazer o upload do excel de pokemon e outra para listar os pokemons do banco.

router.get("/pokemon", excelController.getPokemons);
app.use("/api/excel", router);
};
module.exports = routes;
15 changes: 15 additions & 0 deletions src/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const express = require("express");
const app = express();
const db = require("./models");
const initRoutes = require("./routes/pokemon.routes");
global.__basedir = __dirname + "/..";
app.use(express.urlencoded({ extended: true }));
initRoutes(app);
db.sequelize.sync();
// db.sequelize.sync({ force: true }).then(() => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pode apagar comentários desnecessários

// console.log("Drop and re-sync db.");
// });
let port = 8080;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seria interessante deixar isso em uma variável de ambiente

app.listen(port, () => {
console.log(`Running at localhost:${port}`);
});
Loading