From b0f5defe1cc5ad186107f5a8f4550da4400ccc94 Mon Sep 17 00:00:00 2001 From: Timo John Date: Tue, 16 Jun 2020 02:21:16 +0200 Subject: [PATCH] Search function works as before minus old syntax --- backend/models/getSearchPresets.js | 2 +- backend/models/getSearchResults.js | 31 ++++- backend/models/handleClimateUpdate.js | 3 +- backend/routes/search.js | 9 +- .../getAllRegionsWithClimatePerMonth.js | 0 backend/{models => util}/getClimateMinMax.js | 4 +- .../getClimatePerRegionAndMonth.js | 0 backend/util/oldToNewQuerySyntax.js | 2 +- backend/util/scoreAndSearch.js | 107 ++++++++++++++++++ 9 files changed, 141 insertions(+), 17 deletions(-) rename backend/{models => util}/getAllRegionsWithClimatePerMonth.js (100%) rename backend/{models => util}/getClimateMinMax.js (81%) rename backend/{models => util}/getClimatePerRegionAndMonth.js (100%) diff --git a/backend/models/getSearchPresets.js b/backend/models/getSearchPresets.js index f9899df..3ce091e 100644 --- a/backend/models/getSearchPresets.js +++ b/backend/models/getSearchPresets.js @@ -1,4 +1,4 @@ -module.exports = async (dbConn, name) => { +module.exports = async (dbConn) => { // TODO: Implement pulling data from database const presets = require ("../mockdata/sample-presets.json") const res = presets diff --git a/backend/models/getSearchResults.js b/backend/models/getSearchResults.js index 66ebbd7..1562d42 100644 --- a/backend/models/getSearchResults.js +++ b/backend/models/getSearchResults.js @@ -1,6 +1,29 @@ -module.exports = async (dbConn, name) => { - const res = await dbConn.query( +const base64 = require ("../util/base64.js") +const ss = require ("../util/scoreAndSearch.js") - ); - return res[0]; +module.exports = async (dbConn, 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 queryObj = {} + if (q.temperature) queryObj['temperature_mean_max'] = q.temperature + if (q.percipitation) queryObj['percipitation'] = q.percipitation + if (q.raindays) queryObj['raindays'] = q.raindays + if (q.sunhours) queryObj['sunhours'] = q.sunhours + + ss.scoreAndSearch(q.from, q.to, queryObj, dbConn).then(searchResults => { + response.data = searchResults + res.json(response) + }).catch(e => { + console.log(e) + res.json(e.message) + }) }; \ No newline at end of file diff --git a/backend/models/handleClimateUpdate.js b/backend/models/handleClimateUpdate.js index 92f0f8c..fc6cded 100644 --- a/backend/models/handleClimateUpdate.js +++ b/backend/models/handleClimateUpdate.js @@ -1,7 +1,6 @@ -require('dotenv').config() const axios = require('axios') -// TODO: Automatically retrieve dates via aviable Data +// TODO: Automatically retrieve dates via aviable Data and get rid of random dates const rangeStartDate = '2010-01' // If no date is given, this date will be used as startDate const rangeEndDate = '2018-12'// If no date is given, this date will be used as endDate diff --git a/backend/routes/search.js b/backend/routes/search.js index 3a6b707..c8d17f4 100644 --- a/backend/routes/search.js +++ b/backend/routes/search.js @@ -6,19 +6,14 @@ module.exports = dbConn => { router.get("/api/v1/search", async (req, res) => { const query = req.query.q; if (query != undefined) { - res.json(await getSearchResults(dbConn, query)); + res.json(await getSearchResults(dbConn, req)); } else { res.status(400).send(); } }); router.get("/api/v1/search/presets", async (req, res) => { - const query = req.query.q; - if (query != undefined) { - res.json(await getSearchPresets(dbConn, query)); - } else { - res.status(400).send(); - } + res.json(await getSearchPresets(dbConn)); }); return router; diff --git a/backend/models/getAllRegionsWithClimatePerMonth.js b/backend/util/getAllRegionsWithClimatePerMonth.js similarity index 100% rename from backend/models/getAllRegionsWithClimatePerMonth.js rename to backend/util/getAllRegionsWithClimatePerMonth.js diff --git a/backend/models/getClimateMinMax.js b/backend/util/getClimateMinMax.js similarity index 81% rename from backend/models/getClimateMinMax.js rename to backend/util/getClimateMinMax.js index d05a531..0a756e5 100644 --- a/backend/models/getClimateMinMax.js +++ b/backend/util/getClimateMinMax.js @@ -1,4 +1,4 @@ -async function getClimateMinMax() { +exports.getClimateMinMax = async function (dbConn) { console.log('getClimateMinMax') const sqlMin = `SELECT MIN(temperature_mean) AS temperature_mean, @@ -16,7 +16,7 @@ async function getClimateMinMax() { MAX(raindays) AS raindays, MAX(sunshine) AS sunhours FROM region_climate` - const [qResMin, qResMax] = await Promise.all([getQueryRows(sqlMin), getQueryRows(sqlMax)]) + const [qResMin, qResMax] = await Promise.all([await dbConn.query(sqlMin), await dbConn.query(sqlMax)]) //console.log(qResMin) return { min: qResMin[0], max: qResMax[0] } } \ No newline at end of file diff --git a/backend/models/getClimatePerRegionAndMonth.js b/backend/util/getClimatePerRegionAndMonth.js similarity index 100% rename from backend/models/getClimatePerRegionAndMonth.js rename to backend/util/getClimatePerRegionAndMonth.js diff --git a/backend/util/oldToNewQuerySyntax.js b/backend/util/oldToNewQuerySyntax.js index 004b482..426688e 100644 --- a/backend/util/oldToNewQuerySyntax.js +++ b/backend/util/oldToNewQuerySyntax.js @@ -1,4 +1,4 @@ -function oldToNewQuerySyntax(queries) { +exports.oldToNewQuerySyntax = function (queries) { let res = {} try { if (queries.temperature_mean_max) res.temperature_mean_max = [queries.temperature_mean_max.split(',')[0], queries.temperature_mean_max.split(',')[1]] diff --git a/backend/util/scoreAndSearch.js b/backend/util/scoreAndSearch.js index e69de29..4818238 100644 --- a/backend/util/scoreAndSearch.js +++ b/backend/util/scoreAndSearch.js @@ -0,0 +1,107 @@ +const _ = require('lodash') +const getClimateMinMax = require("./getClimateMinMax.js") +const oldToNewQuerySyntax = require("./oldToNewQuerySyntax.js") +const moment = require("moment") + +exports.scoreAndSearch = async function (from, to, queries, dbConn) { + // TODO break funtion into parts when implementing non-climate queries and modularize (new file) + + console.log('search') + + // get Min and Max values for each Parameter + const minMax = await getClimateMinMax.getClimateMinMax(dbConn) + + // randomize if empty queries + // TODO: WHY + if (_.isEmpty(queries)) { + 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 r = _.round(_.random(minMax.min.raindays, minMax.max.raindays - 5), 0) + let s = _.round(_.random(minMax.min.sunhours, minMax.max.sunhours - 50), 0) + queries.temperature_mean_max = `${t},${t + 5}` + queries.percipitation = `${p},${p + 50}` + queries.raindays = `${r},${r + 5}` + queries.sunhours = `${s},${s + 50}` + } + queries = oldToNewQuerySyntax.oldToNewQuerySyntax(queries) + console.log(queries) + + // TODO simplify and remove support for old query syntaax + let monthFrom = 0 + let monthTo = 0 + let dayFrom = 0 + let dayTo = 0 + + if (_.isNumber(from) && _.isNumber(to)) { + let dateFrom = moment(from).toDate() + let dateTo = moment(to).toDate() + monthFrom = dateFrom.getMonth() + monthTo = dateTo.getMonth() + dayFrom = dateFrom.getDay() + dayTo = dateTo.getDay() + if (moment(dateFrom).add(23, 'hours').isAfter(moment(dateTo))) throw new Error("ERR: 'to' must be at least one day after 'from'.") + } else { + // to still support old query syntax + let re = /([12]\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01]))/i; + monthFrom = Number(from.split("-")[1]) + monthTo = Number(to.split("-")[1]) + dayFrom = Number(from.split("-")[2]) + dayTo = Number(to.split("-")[2]) + if (!from.match(re) || !to.match(re)) throw new Error("ERR: invalid parameter:",from,to) + if (moment(from, 'YYYY-MM-DD').add(23, 'hours').isAfter(moment(to, 'YYYY-MM-DD'))) throw new Error("ERR: 'to' must be at least one day after 'from'.") + } + + // -- Prepare search -- + // to calculate average if traveldates are in more than one month + let travelPeriods = [] + if (monthFrom === monthTo) { + let element = { + month: monthFrom, + days: dayTo - dayFrom + } + travelPeriods.push(element) + } else { + for (let index = monthFrom; index <= monthTo; index++) { + let element = {} + if (index === monthFrom) { + element = { + month: index, + days: 32 - dayFrom + } + } else if (index === monthTo) { + element = { + month: index, + days: dayTo + } + } else { + element = { + month: index, + days: 30 + } + } + travelPeriods.push(element) + } + } + + // calculate detail scores + 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[0], value[1], minMax) + }); + return period + })); + + + // calculate ratio and transform into target object + return { + results: transformer.transform(detailScores), + debug: { + detailScores: detailScores, + minMax: minMax + } + } +} \ No newline at end of file