Skip to content

Instantly share code, notes, and snippets.

@happyrobots
Created June 5, 2013 10:58
Show Gist options
  • Save happyrobots/5713111 to your computer and use it in GitHub Desktop.
Save happyrobots/5713111 to your computer and use it in GitHub Desktop.
# ...
populateAutocompleteForResourceName = (resourceName, done) ->
redisClient = require("redis").createClient()
redisClient.debug_mode = true
sequelize = require('./app/models').sequelize
redisKey = "compl:#{resourceName}"
selectQuery = "SELECT DISTINCT(\"Places\".\"#{resourceName}\") from \"Places\""
sequelize.query(selectQuery).success((resources) ->
multi = redisClient.multi()
for resource in resources
value = resource[resourceName]
len = value.length
for sublen in [1..len] by 1
prefix = value.substring 0, sublen
multi.zadd redisKey, 0, prefix
multi.zadd redisKey, 0, (value+"*")
multi.exec (err, response) ->
redisClient.quit()
done()
).failure((err) ->
console.log "Error querying #{resourceName}: ", err
done()
)
# http://gruntjs.com/api/inside-tasks
# populateAutocomplete:city or populateAutocomplete:postalCode
grunt.registerTask 'populateAutocomplete', ->
done = this.async()
# this.args[0] can be 'city' or 'postalCode'
resourceName = this.args[0]
if resourceName == 'city' || resourceName == 'postalCode'
populateAutocompleteForResourceName resourceName, done
else
console.log "Please run `grunt populateAutocomplete:city` or `grunt populateAutocomplete:postalCode`"
done()
populateAutocompleteResults = (redisKey, prefix, start, rangelen, results, completion) ->
redisClient.zrange(redisKey, start, start+rangelen-1, (err, matches) ->
if err
console.log err
completion(err, null)
return
start += rangelen
if !matches or matches.length == 0
completion(null, results)
return
for entry in matches
minlen = Math.min entry.length, prefix.length
if entry.substring(0, minlen) != prefix.substring(0, minlen)
count = results.count
break
entryLen = entry.length
if entry.charAt(entryLen-1) == '*' and results.length != count
results.push entry.substring(0, entryLen-1)
if results.length == count
completion(null, results)
else
populateAutocompleteResults(redisKey, prefix, start, rangelen, results, completion)
)
respondWithAutocomplete = (term, redisKey, req, res) ->
term = req.query.term
respondWithBadRequest = -> res.send(400, error: { message: "Bad request", statusCode: 400 })
unless term?
respondWithBadRequest()
return
termLowercase = term.toLowerCase()
redisClient.zrank redisKey, termLowercase, (err, rank) ->
if err
respondWithBadRequest()
else
if rank
populateAutocompleteResults redisKey, termLowercase, parseInt(rank, 10), 50, [], (err, result) ->
if err
respondWithBadRequest()
else
result = [] unless result
res.json query: term, suggestions: result.map((item) -> lingo.capitalize(item))
else
res.json query: term, suggestions: []
app.get "/autocomplete/cities.json", passport.authenticate('basic', { session: false }), (req, res) ->
respondWithAutocomplete req.query.term, "compl:city", req, res
app.get "/autocomplete/postalCodes.json", passport.authenticate('basic', { session: false }), (req, res) ->
respondWithAutocomplete req.query.term, "compl:postalCode", req, res
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment