mongoose-taggable-via-redis
Version:
a mongoose plugin provide fast and flexible tagging ablity to datamodle via redis, supports scope tagging
153 lines (116 loc) • 4.29 kB
text/coffeescript
##
# mongoose-taggable-via-redis
# https://github.com/yi/mongoose-taggable-via-redis
#
# Copyright (c) 2014 yi
# Licensed under the MIT license.
##
# default plugin options values
taggable = require "taggable-via-redis"
assert = require "assert"
debuglog = require("debug")("mongoose-taggable")
mongoose = require 'mongoose'
util = require "util"
#mongoose.set('debug', true)
getIdFromResult = (result) -> result._id || result.id
findCallbackFromArguments = (args)->
theCallback = null
for i in [0...args.length]
if "function" is typeof args[i]
return i
return -1
# mongoose-times plugin method
module.exports = exports = (schema, options)->
assert schema, "missing argument: schema"
assert options, "missing argument: options"
assert options.taggable, "missing argument: options.taggable"
# reset redis client if required
taggable.init(options.redisClient) if options.redisClient
schema["__taggable"] = options
schema
.virtual('tags')
.set( (val)->
= val
)
.get( ()-> return this._tags)
# include virtuals in json dump
schema.set('toJSON', { virtuals: true})
schema.set('toObject', { virtuals: true})
## instance methods
# set tags to an instance
schema.methods.setTags = (tags, callback)->
#options = schema.__taggable
debuglog "[setTags] moduleName:#{options.taggable}, id:#{@id}, tags:#{tags}"
#debuglog "[setTags] schema:#{util.inspect(schema, {showHidden:true, colors:true})}"
scope = if options.getScope then options.getScope.apply(@) else null
taggable.set options.taggable, , tags, scope, callback
return
## static methds
# get popular tags of specified amount
schema.statics['popularTags'] = (count, scope, callback)->
debuglog "[popularTags] count:#{count}"
taggable.popular options.taggable, count, scope, callback
return
# find records of given tags
schema.statics['findByTags'] = (tags, query, scope, callback) ->
debuglog "[findByTags] tags:#{tags}, scope:#{scope}"
if 'function' is typeof scope
callback = scope
scope = null
else if 'function' is typeof query
callback = query
scope = null
query = null
taggable.find options.taggable, tags, scope, (err, ids)=>
return callback err if err?
query = (query || @).where _id : $in : ids
query.execWithTag callback
return
return
# find, and return results with tags
schema.statics['findWithTags'] = (conditions, callback) ->
debuglog "[findWithTags]"
if "function" is typeof conditions
callback = conditions
conditions = {}
conditions, (err, results)->
return callback?(err) if err?
# lazy
return callback?(null, results) unless Array.isArray(results) and results.length > 0
ids = results.map getIdFromResult
scope = if options.getScope then options.getScope.apply(results[0]) else null
debuglog "[findWithTags] ids:#{ids}, scope:#{scope}"
taggable.get options.taggable, ids, scope, (err, tagsArray)->
#debuglog "[findWithTags] tagsArray:#{tagsArray}"
return callback?(err) if err?
for object, i in results
object.tags = tagsArray[i]
callback?(null, results)
return
return
## pre/post hooks
schema.post 'remove', (record)->
debuglog "[on remove] record:#{record}"
# remove tags belong to this record
record.setTags null
return
## query extension
# exec, and return results with tags
mongoose.Query::execWithTag = (callback) ->
# getting back the hacked-attached options
taggableOptions = @.model.schema.__taggable
#debuglog "[execWithTag ] what is this: #{util.inspect(taggableOptions)}"
(err, results) =>
return callback?(err) if err?
return callback?(null, results) unless Array.isArray(results) and results.length > 0
ids = results.map getIdFromResult
scope = if taggableOptions.getScope then taggableOptions.getScope.apply(results[0]) else null
taggable.get taggableOptions.taggable, ids, scope, (err, tags)->
return callback?(err) if err?
for object, i in results
object.tags = tags[i]
callback null, results
return
return
return
return