var express = require('express') var _ = require('lodash') var sampledata = require('./sampledata') var db = require('./mysql') var score = require('./score') var transformer = require('./transformer') const app = express() const port = 3000 //const multiplier_temp = 5 const multiplier = { temperature_mean: 5, percipitation: 3.5, raindays: 3, sunhours: 2.5, } const sampleRegions = [ { id: 29837, name: "Timbuktu", country: "Mali" } ] const samplePresets = [ { id: 29837, parameter: "temperature", label: "warm", values: [22, 25] } ] app.get('/', (req, res) => res.send('Hello Timo!')) app.get('/v1/regions', (req, res) => res.json(sampleRegions)) app.get('/v1/presets', (req, res) => res.json(samplePresets)) app.get('/v1/search', (req, res) => { let response = {} response.meta = { params: req.params, query: req.query, headers: req.headers } console.log('log params') console.log(req.query.from) console.log(req.query.to) console.log(req.query.temperature) let validQueries = {} if (req.query.temperature) validQueries['temperature_mean'] = req.query.temperature if (req.query.percipitation) validQueries['percipitation'] = req.query.percipitation if (req.query.raindays) validQueries['raindays'] = req.query.raindays if (req.query.sunhours) validQueries['sunhours'] = req.query.sunhours search(req.query.from, req.query.to, validQueries).then(searchResults => { response.data = searchResults res.json(response) }) }) app.listen(port, () => console.log(`Travopti backend listening at http://localhost:${port}`)) async function search(from, to, queries) { // get Min and Max values for each Parameter const minMax = await getClimateMinMax() // randomize if empty queries if (_.isEmpty(queries)) { let t = _.random(minMax.min.temperature_mean, minMax.max.temperature_mean-5) let p = _.random(minMax.min.percipitation, minMax.max.percipitation-50) let r = _.random(minMax.min.raindays, minMax.max.raindays-5) let s = _.random(minMax.min.sunhours, minMax.max.sunhours-50) queries.temperature_mean = `${t},${t + 5}` queries.percipitation = `${p},${p + 50}` queries.raindays = `${r},${r + 5}` queries.sunhours = `${s},${s + 50}` } console.log('search') // validate regex: YYYY-MM-DD let re = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/i; if (!from.match(re) || !to.match(re)) throw new Error("invalid parameter: " + from + " " + to) // -- Prepare search -- // calculate average if traveldates are in more than one month let monthFrom = Number(from.split("-")[1]) let monthTo = Number(to.split("-")[1]) let travelPeriods = [] let virtDays = 0 if (monthFrom === monthTo) { let element = { month: monthFrom, days: Number(to.split("-")[2]) - Number(from.split("-")[2]) } virtDays = element.days travelPeriods.push(element) } else { for (let index = monthFrom; index <= monthTo; index++) { let element = {} if (index === monthFrom) { element = { month: index, days: 32 - Number(from.split("-")[2]) } } else if (index === monthTo) { element = { month: index, days: Number(to.split("-")[2]) } } else { element = { month: index, days: 30 } } virtDays += element.days travelPeriods.push(element) } } // calculate score let detailScores = await Promise.all(travelPeriods.map(async period => { period.climate = await getAllRegionsWithClimatePerMonth(period.month) period.scores = {} Object.entries(queries).forEach(([key, value]) => { // console.log('key',key) // console.log('val', value) period.scores[key] = calculateScores(key, period.climate, value.split(',')[0], value.split(',')[1], minMax) }); return period })); // TODO: calculate ratio return { results: transformer.transform(detailScores), debug: { detailScores: detailScores, minMax: minMax } } // return { TODO___scores: detailScores } // return { TODO___scores: calculateAverageScore(detailScores, Object.keys(queries)) } } function calculateAverageScore(scorePeriods, types) { const days = scorePeriods.reduce((total, period) => total += period.days) let totalScores = {} let finalRegionObj = { } scorePeriods.forEach(element => { types.forEach(type => { element.scores[type].forEach(regionScore => { }) }) }) } function transformToRegionObjects(scorePeriods) { let response = [] // create region objects scorePeriods[0].climate.forEach(element => { let obj = { region_id: element.region_id, country_id: element.country_id, name: element.name, } response.push(obj) }) // } function calculateScores(type, regionDataRows, searchLowParam, searchMaxParam, minMax) { console.log('calculateScores for', type) // console.log(searchLowParam) // console.log(searchMaxParam) // console.log(minMax) //console.log(regionDataRows) let result = regionDataRows.map(x => { // console.log(x.temperature_mean) 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 } async function getClimateMinMax() { console.log('getClimateMinMax') const sqlMin = `SELECT MIN(temperature_mean) AS temperature_mean, MIN(temperature_mean_min) AS temperature_mean_min, MIN(temperature_mean_max) AS temperature_mean_max, MIN(percipitation) AS percipitation, MIN(raindays) AS raindays, MIN(sunshine) AS sunhours FROM region_climate` const sqlMax = `SELECT MAX(temperature_mean) AS temperature_mean, MAX(temperature_mean_min) AS temperature_mean_min, MAX(temperature_mean_max) AS temperature_mean_max, MAX(percipitation) AS percipitation, MAX(raindays) AS raindays, MAX(sunshine) AS sunhours FROM region_climate` const [qResMin, qResMax] = await Promise.all([getQueryRows(sqlMin), getQueryRows(sqlMax)]) //console.log(qResMin) return { min: qResMin[0], max: qResMax[0] } } async function getQueryRows(sql) { //console.log('getQueryRows') const [rows, fields] = await db.execute(sql) return rows } function getRegionIdsWithMeteostatData() { console.log('getRegionIdsWithMeteostatData') //return await getQueryRows(`SELECT * FROM regions WHERE meteostat_id IS NOT NULL`) return getQueryRows(`SELECT region_id FROM region_climate GROUP BY region_id`) } function getClimatePerRegionAndMonth(regionId, month) { console.log('getClimatePerRegionAndMonth') const sql = `SELECT region_id, AVG(temperature_mean), AVG(temperature_mean_min), AVG(temperature_mean_max), AVG(percipitation), AVG(sunshine) FROM region_climate WHERE month = ${month} AND region_id = ${regionId}` return getQueryRows(sql) } function getAllRegionsWithClimatePerMonth(month) { console.log('getAllRegionsWithClimatePerMonth') const sql = `SELECT region_climate.region_id AS region_id, regions.country_id AS country_id, regions.region AS name, 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_max), 1) AS temperature_mean_max, ROUND(AVG(region_climate.percipitation), 1) AS percipitation, ROUND(AVG(region_climate.raindays), 1) AS raindays, 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` return getQueryRows(sql) }