changed query syntax
This commit is contained in:
parent
4f4d51b514
commit
eb5491b64b
149
backend/app.js
149
backend/app.js
@ -1,11 +1,11 @@
|
||||
var express = require('express')
|
||||
var _ = require('lodash')
|
||||
var sampledata = require('./sampledata')
|
||||
var db = require('./mysql')
|
||||
var score = require('./score')
|
||||
var transformer = require('./transformer')
|
||||
var climate = require('./climate')
|
||||
var moment = require('moment')
|
||||
const express = require('express')
|
||||
const moment = require('moment')
|
||||
const _ = require('lodash')
|
||||
const db = require('./mysql')
|
||||
const score = require('./score')
|
||||
const transformer = require('./transformer')
|
||||
const climate = require('./climate')
|
||||
const base = require('./base64')
|
||||
|
||||
const app = express()
|
||||
const port = 3000
|
||||
@ -17,13 +17,6 @@ const multiplier = {
|
||||
sunhours: 2.5,
|
||||
}
|
||||
|
||||
const sampleRegions = [
|
||||
{
|
||||
id: 29837,
|
||||
name: "Timbuktu",
|
||||
country: "Mali"
|
||||
}
|
||||
]
|
||||
const samplePresets = [
|
||||
{
|
||||
id: 29837,
|
||||
@ -34,8 +27,8 @@ const samplePresets = [
|
||||
]
|
||||
|
||||
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/regions', (req, res) => getAllRegions().then(x => res.json({ data: x })))
|
||||
app.get('/v1/presets', (req, res) => res.json({ data: samplePresets}))
|
||||
app.get('/v1/search', searchHandler)
|
||||
app.get('/v1/update/climate', climateUpdateHandler)
|
||||
|
||||
@ -60,25 +53,23 @@ function climateUpdateHandler(req, res) {
|
||||
|
||||
function searchHandler(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 => {
|
||||
|
||||
let q = req.query.q ? base.base64ToObj(req.query.q) : req.query
|
||||
console.log('Q:', q)
|
||||
|
||||
let queryObj = {}
|
||||
if (q.temperature) queryObj['temperature_mean'] = q.temperature
|
||||
if (q.percipitation) queryObj['percipitation'] = q.percipitation
|
||||
if (q.raindays) queryObj['raindays'] = q.raindays
|
||||
if (q.sunhours) queryObj['sunhours'] = q.sunhours
|
||||
|
||||
scoreAndSearch(q.from, q.to, queryObj).then(searchResults => {
|
||||
response.data = searchResults
|
||||
res.json(response)
|
||||
}).catch(e => {
|
||||
@ -87,42 +78,60 @@ function searchHandler(req, res) {
|
||||
})
|
||||
}
|
||||
|
||||
async function search(from, to, queries) {
|
||||
async function scoreAndSearch(from, to, queries) {
|
||||
// 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()
|
||||
|
||||
// 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)
|
||||
let t = _.round(_.random(minMax.min.temperature_mean, minMax.max.temperature_mean-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 = `${t},${t + 5}`
|
||||
queries.percipitation = `${p},${p + 50}`
|
||||
queries.raindays = `${r},${r + 5}`
|
||||
queries.sunhours = `${s},${s + 50}`
|
||||
}
|
||||
// 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("ERR: invalid parameter:",from,to)
|
||||
// check for valid period
|
||||
if (moment(from, 'YYYY-MM-DD').isAfter(moment(to, 'YYYY-MM-DD'))) {
|
||||
console.log(moment(from, 'YYYY-MM-DD'))
|
||||
console.log(moment(to, 'YYYY-MM-DD'))
|
||||
console.log(moment(from, 'YYYY-MM-DD').isAfter(moment(to, 'YYYY-MM-DD')))
|
||||
throw new Error("ERR: from is before to date.")
|
||||
queries = 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 --
|
||||
// calculate average if traveldates are in more than one month
|
||||
let monthFrom = Number(from.split("-")[1])
|
||||
let monthTo = Number(to.split("-")[1])
|
||||
|
||||
// to calculate average if traveldates are in more than one month
|
||||
let travelPeriods = []
|
||||
if (monthFrom === monthTo) {
|
||||
let element = {
|
||||
month: monthFrom,
|
||||
days: Number(to.split("-")[2]) - Number(from.split("-")[2])
|
||||
days: dayTo - dayFrom
|
||||
}
|
||||
travelPeriods.push(element)
|
||||
} else {
|
||||
@ -131,12 +140,12 @@ async function search(from, to, queries) {
|
||||
if (index === monthFrom) {
|
||||
element = {
|
||||
month: index,
|
||||
days: 32 - Number(from.split("-")[2])
|
||||
days: 32 - dayFrom
|
||||
}
|
||||
} else if (index === monthTo) {
|
||||
element = {
|
||||
month: index,
|
||||
days: Number(to.split("-")[2])
|
||||
days: dayTo
|
||||
}
|
||||
} else {
|
||||
element = {
|
||||
@ -148,20 +157,20 @@ async function search(from, to, queries) {
|
||||
}
|
||||
}
|
||||
|
||||
// calculate score
|
||||
// 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.split(',')[0], value.split(',')[1], minMax)
|
||||
period.scores[key] = calculateScores(key, period.climate, value[0], value[1], minMax)
|
||||
});
|
||||
return period
|
||||
}));
|
||||
|
||||
|
||||
// TODO: calculate ratio
|
||||
// calculate ratio and transform into target object
|
||||
return {
|
||||
results: transformer.transform(detailScores),
|
||||
debug: {
|
||||
@ -216,10 +225,17 @@ async function getQueryRows(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 getAllRegions() {
|
||||
const sql = `SELECT
|
||||
regions.id AS region_id,
|
||||
regions.region AS name,
|
||||
regions.country_id AS country_id,
|
||||
countries.country AS country,
|
||||
regions.meteostat_id AS meteostat_id
|
||||
FROM regions
|
||||
JOIN countries
|
||||
ON regions.country_id = countries.id`
|
||||
return getQueryRows(sql)
|
||||
}
|
||||
|
||||
function getClimatePerRegionAndMonth(regionId, month) {
|
||||
@ -242,4 +258,19 @@ function getAllRegionsWithClimatePerMonth(month) {
|
||||
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)
|
||||
}
|
||||
|
||||
function oldToNewQuerySyntax(queries) {
|
||||
let res = {}
|
||||
try {
|
||||
if (queries.temperature_mean) res.temperature_mean = [queries.temperature_mean.split(',')[0], queries.temperature_mean.split(',')[1]]
|
||||
if (queries.percipitation) res.percipitation = [queries.percipitation.split(',')[0], queries.percipitation.split(',')[1]]
|
||||
if (queries.raindays) res.raindays = [queries.raindays.split(',')[0], queries.raindays.split(',')[1]]
|
||||
if (queries.sunhours) res.sunhours = [queries.sunhours.split(',')[0], queries.sunhours.split(',')[1]]
|
||||
console.log('queries successfully transformed');
|
||||
} catch (error) {
|
||||
console.log('queries are ok');
|
||||
return queries
|
||||
}
|
||||
return res
|
||||
}
|
||||
23
backend/base64.js
Normal file
23
backend/base64.js
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Encodes an object as base64 string..
|
||||
* @param obj The object to encode
|
||||
*/
|
||||
exports.objToBase64 = function(obj) {
|
||||
return btoa(JSON.stringify(obj));
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a base64 encoded object.
|
||||
* @param base64 Encoded object
|
||||
*/
|
||||
exports.base64ToObj = function(base64) {
|
||||
return JSON.parse(atob(base64));
|
||||
}
|
||||
|
||||
function atob(base64) {
|
||||
return Buffer.from(base64, 'base64').toString('binary')
|
||||
}
|
||||
|
||||
function btoa(string) {
|
||||
return Buffer.from(string).toString('base64')
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user