const router = require("express").Router(); // Models const getRegions = require('../models/getRegions.js'); const getSearchPresets = require("../models/getSearchPresets.js"); // Utils const _ = require('lodash') const base64 = require("../util/base64.js") const scoreAndSearch = require("../util/scoreAndSearch.js"); const oldToNewQuerySyntax = require("../util/oldToNewQuerySyntax.js") const { allTagsWithValues, getUniqueTags } = require("../models/getTags.js"); const { getClimateMinMax } = require("../util/getClimateMinMax.js"); module.exports = dbConn => { router.get("/api/v1/search", searchHandler(dbConn)); router.get("/api/v1/search/presets", presetHandler(dbConn)); router.get("/api/v1/search/tags", tagsHandler(dbConn)); return router; }; function tagsHandler(dbConn) { return function (req, res) { getUniqueTags(dbConn).then(tags => { res.json(tags.map(tag => tag.name)) }).catch(error => { // TODO error handling }) } } function presetHandler(dbConn) { return function (req, res) { getSearchPresets(dbConn).then(presets => { res.json(presets) }).catch(error => { // TODO error handling }) } } function searchHandler(dbConn) { return async function (req, res) { let response = {} response.meta = { params: req.params, query: req.query, headers: req.headers } // SWITCH TO SUPPORT OLD AND NEW BASE64 BASED QUERY SYNTAX let q = req.query.q ? base64.base64ToObj(req.query.q) : req.query console.log('Q:', q) // transform syntax and seperate climate queries from price queries if (!req.query.q) { q = oldToNewQuerySyntax(q) } // CHOOSE PARAMS WHICH SHALL BE PASSED TO SCORE AND SEARCH let scoreQueryObj = prepareQueries(q) let [regions, boundaryClimate] = await Promise.all([getRegions(dbConn), getClimateMinMax(dbConn)]) let data = { regions: regions, boundaryClimate: boundaryClimate } // FILTER if query contains filterString if (q.textfilter) { data.regions = filterByString(data.regions, q.textfilter, q.fulltext) } scoreAndSearch(data, q.from, q.to, scoreQueryObj).then(searchResults => { // only dev: if (process.env.SHOW_MATCH_VALUE === '1') searchResults.forEach(reg => reg.name = `${reg.name} (${_.round(reg.score * 10, 1)}% match)`) // FILTER NULLSCORES if (!_.get(q, 'showRegionsWithNullScore', false)) { console.log('without null scores'); searchResults.forEach(el => console.log('region:', el.name, 'score:', el.score)) searchResults = searchResults.filter(el => !_.some(el.scores, score => _.isNaN(score.score) || _.isNil(score.score) || score.score <= 0)) // searchResults = searchResults.filter(el => !(_.isNil(el.score) || _.isNaN(el.score)) ) // searchResults = searchResults.filter(el => { // let nullcnt = 0 // el.scores.forEach(sc => { // if (_.isNaN(sc.score) || sc.score <= 0 || _.isNil(el.score)) { // nullcnt++ // } // }) // console.log(el.name, nullcnt) // return nullcnt >= 2 ? false : true // }) /*searchResults = searchResults.filter(el => { console.log('scorrrrrr', el.score); let keepIt = true //if (_.some(el.scores, score => score.score <= 0) && el.score < 1) keepIt = false return cutScores ? keepIt : true })//.filter(el => !_.isNaN(el.score))*/ } // SEND RESPONSE // response.data = searchResults // res.json(response) res.json(searchResults) }).catch(e => { // TODO error handling console.log(e) res.status(400).send(e.message) }) } } function filterByString(searchResults, filterString, boolFulltext) { return _.filter(searchResults, region => { // console.log("filtering: filterString, boolFulltext"); // console.log(filterString, boolFulltext); filterString = filterString.toLowerCase() let name = region.name.toLowerCase() let country = region.country.toLowerCase() if (boolFulltext) { let desc = region.description.toLowerCase() return name.includes(filterString) || country.includes(filterString) || desc.includes(filterString) } return name.includes(filterString) || country.includes(filterString) }) } function prepareQueries(queries) { let q = { climate: {}, costs: {}, others: {} } // climate if (queries.temperature_mean_max) q.climate.temperature_mean_max = queries.temperature_mean_max if (queries.precipitation) q.climate.precipitation = queries.precipitation if (queries.rain_days) q.climate.rain_days = queries.rain_days if (queries.sun_hours) q.climate.sun_hours = queries.sun_hours // costs if (queries.accommodation_costs) q.costs.accommodation_costs = queries.accommodation_costs if (queries.food_costs) q.costs.food_costs = queries.food_costs if (queries.alcohol_costs) q.costs.alcohol_costs = queries.alcohol_costs if (queries.water_costs) q.costs.water_costs = queries.water_costs if (queries.local_transportation_costs) q.costs.local_transportation_costs = queries.local_transportation_costs if (queries.entertainment_costs) q.costs.entertainment_costs = queries.entertainment_costs if (queries.average_per_day_costs) q.costs.average_per_day_costs = queries.average_per_day_costs // others if (queries.avg_price_relative) q.others.avg_price_relative = queries.avg_price_relative if (queries.tags) q.others.tags = queries.tags return q }