finished refactoring

This commit is contained in:
Timo Volkmann 2020-06-16 14:31:46 +02:00
parent e1ef3c4a9a
commit 4b978842f7
11 changed files with 207 additions and 137 deletions

22
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,22 @@
{
// Verwendet IntelliSense zum Ermitteln möglicher Attribute.
// Zeigen Sie auf vorhandene Attribute, um die zugehörigen Beschreibungen anzuzeigen.
// Weitere Informationen finden Sie unter https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"name": "NodeJS: nodemon debug",
"program": "${workspaceFolder}/backend/index.js",
"request": "launch",
"restart": true,
"runtimeExecutable": "nodemon",
"skipFiles": [
"<node_internals>/**"
],
"type": "node",
"envFile": "${workspaceFolder}/backend/.env",
}
]
}

View File

@ -4,7 +4,6 @@ const path = require("path");
const morgan = require("morgan"); const morgan = require("morgan");
const dbConnection = require("./util/dbConnection"); const dbConnection = require("./util/dbConnection");
const fs = require("fs"); const fs = require("fs");
const httpolyglot = require("httpolyglot");
require('dotenv').config() require('dotenv').config()
// credentials // credentials

View File

@ -2,9 +2,6 @@ module.exports = async (dbConn) => {
const regions = await dbConn.query( const regions = await dbConn.query(
`SELECT regions.id AS region_id, `SELECT regions.id AS region_id,
regions.region AS name, regions.region AS name,
regions.description,
regions.preview_img,
regions.country_id AS country_id,
countries.country AS country, countries.country AS country,
regions.meteostat_id AS meteostat_id regions.meteostat_id AS meteostat_id
FROM regions FROM regions

View File

@ -1,11 +1,15 @@
const router = require("express").Router(); const router = require("express").Router();
const getRegions = require("../models/getRegions.js"); const getRegions = require("../models/getRegions.js");
const getRegionById = require("../models/getRegionById.js"); const getRegionById = require("../models/getRegionById.js");
const path = require("path");
module.exports = dbConn => { module.exports = dbConn => {
router.get("/api/v1/regions", async (req, res) => { router.get("/api/v1/regions", async (req, res) => {
res.json(await getRegions(dbConn)); res.json(await getRegions(dbConn));
}); });
router.get('/api/v1/regions/:id/image', (req, res) => {
res.sendFile(path.join(__dirname, `../data/regions/images/${req.params.id}.jpg`))
})
router.get("/api/v1/regions/:id", async (req, res) => { router.get("/api/v1/regions/:id", async (req, res) => {
const id = req.params.id; const id = req.params.id;

View File

@ -1,20 +1,60 @@
const router = require("express").Router(); const router = require("express").Router();
const getSearchResults = require("../models/getSearchResults.js"); const _ = require('lodash')
const getSearchPresets = require("../models/getSearchPresets.js"); const getSearchPresets = require("../models/getSearchPresets.js");
const base64 = require("../util/base64.js")
const sas = require("../util/scoreAndSearch.js")
module.exports = dbConn => { module.exports = dbConn => {
router.get("/api/v1/search", async (req, res) => { router.get("/api/v1/search", searchHandler(dbConn));
const query = req.query.q; router.get("/api/v1/search/presets", presetHandler(dbConn));
if (query != undefined) {
res.json(await getSearchResults(dbConn, req));
} else {
res.status(400).send();
}
});
router.get("/api/v1/search/presets", async (req, res) => {
res.json(await getSearchPresets(dbConn));
});
return router; return router;
}; };
function presetHandler(dbConn) {
return function (req, res) {
getSearchPresets(dbConn).then(presets => {
res.json(presets)
}).catch(error => {
// TODO error handling
})
}
}
function searchHandler(dbConn) {
const scoreAndSearch = sas(dbConn)
return function (req, res) {
let response = {}
response.meta = {
params: req.params,
query: req.query,
headers: req.headers
}
let q = req.query.q ? base64.base64ToObj(req.query.q) : req.query
console.log('Q:', q)
let scoreQueryObj = {}
if (q.temperature) scoreQueryObj['temperature_mean_max'] = q.temperature
if (q.percipitation) scoreQueryObj['percipitation'] = q.percipitation
if (q.raindays) scoreQueryObj['raindays'] = q.raindays
if (q.sunhours) scoreQueryObj['sunhours'] = q.sunhours
// @TimoJ 1. hier die Parameter die gescored werden sollen hinufügen
if (_.isEmpty(scoreQueryObj)) {
res.status(400).send('provide at least one search parameter.');
}
scoreAndSearch(q.from, q.to, scoreQueryObj).then(searchResults => {
// TODO hier könnten Suchergebnisse gefiltert werden: für Textsuche oder Exludes....
response.data = searchResults
res.json(response)
}).catch(e => {
// TODO error handling
console.log(e)
res.json(e.message)
})
}
}

View File

@ -1,15 +0,0 @@
function calculateScores(type, regionDataRows, searchLowParam, searchMaxParam, minMax) {
console.log('calculateScores for', type)
let result = regionDataRows.map(x => {
const sc = Math.round(score.calculateScoreRange(minMax.min[type], minMax.max[type], multiplier[type], x[type], searchLowParam, searchMaxParam) * 100) / 100
return {
region_id: x.region_id,
type: type,
value: x[type],
score: x[type] === null ? null : sc
}
})
return result
}

View File

@ -1,8 +1,11 @@
function getAllRegionsWithClimatePerMonth(month) {
module.exports = function (dbConn) {
return async function getAllRegionsWithClimatePerMonth(month) {
console.log('getAllRegionsWithClimatePerMonth') console.log('getAllRegionsWithClimatePerMonth')
const sql = `SELECT const sql = `SELECT
region_climate.region_id AS region_id, region_climate.region_id AS region_id,
regions.country_id AS country_id, countries.country AS country,
regions.region AS name, regions.region AS name,
ROUND(AVG(region_climate.temperature_mean), 1) AS temperature_mean, ROUND(AVG(region_climate.temperature_mean), 1) AS temperature_mean,
ROUND(AVG(region_climate.temperature_mean_min), 1) AS temperature_mean_min, ROUND(AVG(region_climate.temperature_mean_min), 1) AS temperature_mean_min,
@ -10,6 +13,13 @@ function getAllRegionsWithClimatePerMonth(month) {
ROUND(AVG(region_climate.percipitation), 1) AS percipitation, ROUND(AVG(region_climate.percipitation), 1) AS percipitation,
ROUND(AVG(region_climate.raindays), 1) AS raindays, ROUND(AVG(region_climate.raindays), 1) AS raindays,
ROUND(AVG(region_climate.sunshine), 1) AS sunhours ROUND(AVG(region_climate.sunshine), 1) AS sunhours
FROM region_climate JOIN regions ON region_climate.region_id = regions.id WHERE region_climate.month = ${month} GROUP BY region_id` FROM region_climate
return getQueryRows(sql) JOIN regions ON region_climate.region_id = regions.id
JOIN countries ON regions.country_id = countries.id
WHERE region_climate.month = ${month} GROUP BY region_id`
let response = await dbConn.query(sql)
console.log(response[0]);
return response
}
} }

View File

@ -16,7 +16,7 @@ exports.getClimateMinMax = async function (dbConn) {
MAX(raindays) AS raindays, MAX(raindays) AS raindays,
MAX(sunshine) AS sunhours MAX(sunshine) AS sunhours
FROM region_climate` FROM region_climate`
const [qResMin, qResMax] = await Promise.all([await dbConn.query(sqlMin), await dbConn.query(sqlMax)]) const [qResMin, qResMax] = await Promise.all([dbConn.query(sqlMin), dbConn.query(sqlMax)])
// console.log(qResMin) // console.log(qResMin)
return { min: qResMin[0], max: qResMax[0] } return { min: qResMin[0], max: qResMax[0] }
} }

View File

@ -1,13 +1,3 @@
/**
*
*/
const multiplier_temperature = 5;
/**
*
* @param {...any} scores expects objects which contains score and their weight
*/
exports.calculateAvgScore = (...scores) => { exports.calculateAvgScore = (...scores) => {
return avgScore = scores.reduce((total, score) => total += score) / scores.length; return avgScore = scores.reduce((total, score) => total += score) / scores.length;
} }
@ -18,14 +8,10 @@ exports.calculateScoreRange = (min, max, multiplier, regionVal, sLowVal, sHighVa
if (regionVal >= sLowVal && regionVal <= sHighVal) return 10; if (regionVal >= sLowVal && regionVal <= sHighVal) return 10;
// choose value with smallest distance // choose value with smallest distance
let sVal = Math.abs(regionVal - sLowVal) < Math.abs(regionVal - sHighVal) ? sLowVal : sHighVal; let sVal = Math.abs(regionVal - sLowVal) < Math.abs(regionVal - sHighVal) ? sLowVal : sHighVal;
//console.log('nearest value',sVal, regionVal)
return this.calculateScore(min, max, multiplier, regionVal, sVal); return this.calculateScore(min, max, multiplier, regionVal, sVal);
} }
exports.calculateScore = (min, max, multiplier, regionVal, searchVal) => { exports.calculateScore = (min, max, multiplier, regionVal, searchVal) => {
let score = 1 - (Math.abs(searchVal - regionVal) / (max - min) * multiplier); let score = 1 - (Math.abs(searchVal - regionVal) / (max - min) * multiplier);
return score <= 0 ? 0 : score * 10; return score <= 0 ? 0 : score * 10;
} }
console.log('test score calculation. result: ' + this.calculateScoreRange(-15, 45, 5, 24, 15, 22))

View File

@ -1,19 +1,27 @@
const _ = require('lodash') const _ = require('lodash')
const moment = require("moment")
const getClimateMinMax = require("./getClimateMinMax.js") const getClimateMinMax = require("./getClimateMinMax.js")
const oldToNewQuerySyntax = require("./oldToNewQuerySyntax.js") const oldToNewQuerySyntax = require("./oldToNewQuerySyntax.js")
const moment = require("moment") const getAllRegionsWithClimatePerMonth = require('./getAllRegionsWithClimatePerMonth')
const score = require('./score')
const transformer = require('./transformer')
exports.scoreAndSearch = async function (from, to, queries, dbConn) { const MULTIPLIER = {
// TODO break funtion into parts when implementing non-climate queries and modularize (new file) temperature_mean_max: 5,
percipitation: 3.5,
raindays: 3,
sunhours: 2.5,
}
module.exports = function (dbConn) {
return async function (from, to, queries) {
console.log('search') console.log('search')
// get Min and Max values for each Parameter // get Min and Max values for each Parameter
const minMax = await getClimateMinMax.getClimateMinMax(dbConn) const minMax = await getClimateMinMax.getClimateMinMax(dbConn)
// randomize if empty queries // randomize if query contains randomize=true
// TODO: WHY if (queries.randomize) {
if (_.isEmpty(queries)) {
let t = _.round(_.random(minMax.min.temperature_mean_max, minMax.max.temperature_mean_max - 5), 0) let t = _.round(_.random(minMax.min.temperature_mean_max, minMax.max.temperature_mean_max - 5), 0)
let p = _.round(_.random(minMax.min.percipitation, minMax.max.percipitation - 50), 0) let p = _.round(_.random(minMax.min.percipitation, minMax.max.percipitation - 50), 0)
let r = _.round(_.random(minMax.min.raindays, minMax.max.raindays - 5), 0) let r = _.round(_.random(minMax.min.raindays, minMax.max.raindays - 5), 0)
@ -22,6 +30,7 @@ exports.scoreAndSearch = async function (from, to, queries, dbConn) {
queries.percipitation = `${p},${p + 50}` queries.percipitation = `${p},${p + 50}`
queries.raindays = `${r},${r + 5}` queries.raindays = `${r},${r + 5}`
queries.sunhours = `${s},${s + 50}` queries.sunhours = `${s},${s + 50}`
delete queries.randomize
} }
queries = oldToNewQuerySyntax.oldToNewQuerySyntax(queries) queries = oldToNewQuerySyntax.oldToNewQuerySyntax(queries)
console.log(queries) console.log(queries)
@ -85,12 +94,12 @@ exports.scoreAndSearch = async function (from, to, queries, dbConn) {
// calculate detail scores // calculate detail scores
let detailScores = await Promise.all(travelPeriods.map(async period => { let detailScores = await Promise.all(travelPeriods.map(async period => {
period.climate = await getAllRegionsWithClimatePerMonth(period.month) period.climate = await getAllRegionsWithClimatePerMonth(dbConn)(period.month)
period.scores = {} period.scores = {}
Object.entries(queries).forEach(([key, value]) => { Object.entries(queries).forEach(([key, value]) => {
// console.log('key',key) // console.log('key',key)
// console.log('val', value) // console.log('val', value)
period.scores[key] = calculateScores(key, period.climate, value[0], value[1], minMax) period.scores[key] = calculateScoresWrapper(key, period.climate, value[0], value[1], minMax)
}); });
return period return period
})); }));
@ -105,3 +114,20 @@ exports.scoreAndSearch = async function (from, to, queries, dbConn) {
} }
} }
} }
function calculateScoresWrapper(type, regionDataRows, searchLowParam, searchMaxParam, minMax) {
console.log('calculateScores for', type)
let result = regionDataRows.map(x => {
const sc = Math.round(score.calculateScoreRange(minMax.min[type], minMax.max[type], MULTIPLIER[type], x[type], searchLowParam, searchMaxParam) * 100) / 100
return {
region_id: x.region_id,
type: type,
value: x[type],
score: x[type] === null ? null : sc
}
})
return result
}
}

View File

@ -9,10 +9,11 @@ exports.transform = (data) => {
// STEP 1 Create Response Array with region names from first climate object // STEP 1 Create Response Array with region names from first climate object
let byRegion = data[0].climate.map(el => { let byRegion = data[0].climate.map(el => {
// return el
return { return {
region_id: el.region_id, region_id: el.region_id,
country_id: el.country_id,
name: el.name, name: el.name,
country: el.country,
} }
}) })