From b526d963fb4d216dff5134422ef1210ca5147ef1 Mon Sep 17 00:00:00 2001 From: Gilles De Mey Date: Sun, 21 Dec 2014 19:11:09 +0100 Subject: [PATCH] Added simple levenshtein distance algorithm to stations route --- db/stations.js | 27 +++++++++++++++++++++++- package.json | 1 + routes/stations.js | 52 +++++++++++++++++++++++++++++++++------------- utils/error.js | 4 ++++ 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/db/stations.js b/db/stations.js index a6c7d65..d3ad9af 100644 --- a/db/stations.js +++ b/db/stations.js @@ -2,7 +2,8 @@ var redis = require('redis'), client = redis.createClient(), - _ = require('lodash-node'); + _ = require('lodash-node'), + leven = require('leven'); exports.byId = function(id, callback) { client.hgetall('station:' + id, function(err, station) { @@ -27,3 +28,27 @@ exports.deserialize = function(object) { return object; }; + +/** + * Lookup the ID of a train station based on the Levenshtein distance algo + */ +exports.levenLookup = function(needle, callback) { + + client.HGETALL(['station:names'], function(err, stations) { + + if (err) + return callback(err); + + var results = []; + + // itterate over stations to find lowest levenshtein distance string + _.forOwn(stations, function(id, station) { + var score = leven(needle, station); + if (score < 5 ) // if the score is larger than 5, it's probably nonsense + results.push({ score: score, id: id, station: station }); + }); + + return callback(null, _.min(results, 'score')); + }); + +}; diff --git a/package.json b/package.json index a0b7025..85777f4 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "debug": "~0.7.4", "express": "~4.2.0", "hiredis": "^0.1.17", + "leven": "^1.0.1", "locale": "0.0.17", "lodash-node": "^2.4.1", "moment": "^2.8.1", diff --git a/routes/stations.js b/routes/stations.js index 9f83c16..fd525c8 100644 --- a/routes/stations.js +++ b/routes/stations.js @@ -1,29 +1,17 @@ 'use strict'; var express = require('express'), + ex = require('../utils/error'), request = require('request'), router = express.Router(), _ = require('lodash-node'), maps = require('../maps'), utils = require('../utils'), datetime = require('../utils/datetime'), + db = require('../db/stations'), OAuth = require('../utils/oauth'); -/* GET status */ -router.get('/:id([0-9]+)/:subset(arrivals|departures)?', function(req, res, next) { - - var dateTimeFrom = datetime.toCET().format('YYYY-MM-DD HH:mm:ss'); - - var dateTimeTo = datetime.toCET() - .add(1, 'hours') - .format('YYYY-MM-DD HH:mm:ss'); - - var params = { - 'dateTimeFrom' : dateTimeFrom, - 'dateTimeTo' : dateTimeTo, - 'searchType' : 0, - 'stationID' : req.params.id - }; +function makeRequest(req, res, next, params) { request.get(new OAuth('RetrieveStationSchedule', params), function(err, resp, body) { @@ -65,6 +53,40 @@ router.get('/:id([0-9]+)/:subset(arrivals|departures)?', function(req, res, next }); }); +} + +/* GET status */ +router.get('/:station/:subset(arrivals|departures)?', function(req, res, next) { + + var dateTimeFrom = datetime.toCET().format('YYYY-MM-DD HH:mm:ss'); + + var dateTimeTo = datetime.toCET() + .add(1, 'hours') + .format('YYYY-MM-DD HH:mm:ss'); + + var params = { + 'dateTimeFrom' : dateTimeFrom, + 'dateTimeTo' : dateTimeTo, + 'searchType' : 0, + }; + + if (isFinite(req.params.station)) { + params.stationID = req.params.station; + makeRequest(req, res, next, params); + } + + else if (isNaN(req.params.station)) + db.levenLookup(req.params.station, function(err, result) { + + params.stationID = result.id; + + // no results from lookup returns Infinity + if (isFinite(result.score)) + makeRequest(req, res, next, params); + else + return res.json(404, new ex.StationNotFoundException()); + }); + }); /* GET index */ diff --git a/utils/error.js b/utils/error.js index 10b60ff..c6503e7 100644 --- a/utils/error.js +++ b/utils/error.js @@ -8,6 +8,10 @@ exports.UnknownException = function(msg, code) { return new exports.Exception(msg, undefined, code); }; +exports.StationNotFoundException = function() { + return new exports.Exception('Could not find station', 'StationNotFoundException', 404); +}; + exports.Exception = function(msg, type, code) { return { 'error' : {