Skip to content

Instantly share code, notes, and snippets.

@royw
Created October 10, 2009 18:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save royw/206993 to your computer and use it in GitHub Desktop.
Save royw/206993 to your computer and use it in GitHub Desktop.
require 'mongo_mapper'
require 'spec'
require 'log4r'
require 'versionomy'
# Logger used for logging MongoDB database commands
Log4r::Logger.new('TMP')
Log4r::Logger['TMP'].outputters = Log4r::StdoutOutputter.new(:console)
Log4r::Outputter[:console].formatter = Log4r::PatternFormatter.new(:pattern => "%m")
Log4r::Logger['TMP'].level = Log4r::DEBUG
# Monkey patch the driver to get buildinfo which contains the version of the MongoDB server
# The version is checked because saving functions on the server requires MongoDB 1.1.1 or newer
module Mongo
class Admin
def buildinfo
oh = OrderedHash.new
oh[:buildinfo] = 1
doc = @db.db_command(oh)
raise "Error with buildinfo command: #{doc.inspect}" unless @db.ok?(doc)
doc
end
end
end
# connect with a logger! Whoooop! Great feature
MongoMapper.connection = Mongo::Connection.new('localhost', nil, :logger => Log4r::Logger['TMP'])
# grab the version from the admin database
MongoMapper.database = 'admin'
mongo_version = Versionomy.parse(MongoMapper.database.admin.buildinfo['version'])
# now switch to our testing database
MongoMapper.database = 'test'
# test model
class Test
include MongoMapper::Document
key :first, Integer
key :second, Integer
end
describe '$where usage' do
before :all do
Log4r::Logger['TMP'].debug { 'writing server-side functions' }
# remove any functions saved on the server
MongoMapper.database.eval(Mongo::Code.new('db.system.js.remove({});'))
end
before :each do
Log4r::Logger['TMP'].debug { 'setting up initial database contents' }
# clean database for each test
Test.collection.clear
Test.create(:first => 10, :second => 15)
Test.create(:first => 17, :second => 23)
end
it "should run js evals" do
Log4r::Logger['TMP'].debug { 'should run js evals' }
MongoMapper.database.eval(Mongo::Code.new('function(){ return 11 + 6; }')).should == 17
MongoMapper.database.eval(Mongo::Code.new('function( x ){ return 10 + x; }'), 7).should == 17
# notice that the Mongo::Code.new() is not necessary
MongoMapper.database.eval('function( z ){ return 17 + z; }', 5).should == 22
end
it "should run server-side functions" do
Log4r::Logger['TMP'].debug { 'should run server-side functions' }
Test.count.should == 2
Test.all(:conditions => {'$where' => Mongo::Code.new("this.first + this.second > 30;")}).size.should == 1
Test.all(:conditions => {'$where' => "this.first + this.second > 30;"}).size.should == 1
Test.all(:conditions => {:first => {'$gt' => 15}}).size.should == 1
# can't get the function(x){...} notation to work
# Test.all(:conditions => {'$where' => Mongo::Code.new("function( a ){ return a.first > 15; }")}).size.should == 1
#
# RuntimeError in 'Wishful Thinking should run server-side functions'
# error on invocation of $where function:
# JS Error: TypeError: a has no properties nofile_b:0
#
# server reports:
# Sat Oct 10 01:06:56 tmp.tests Caught Assertion in runQuery ns:tmp.tests massert:error on invocation of $where function:
# JS Error: TypeError: a has no properties nofile_b:0
end
it "should store and run server-side functions" do
Log4r::Logger['TMP'].debug { 'should store and run server-side functions' }
# storing functions on the server side requires MongoDB 1.1.1 or newer
minimum_mongo_version = Versionomy.parse('1.1.1')
(mongo_version <=> minimum_mongo_version).should >= 0
# with or without Mongo::Code.new
MongoMapper.database.eval(Mongo::Code.new('db.system.js.count();')).should == 0
MongoMapper.database.eval('db.system.js.count();').should == 0
# need to add the following server-side function:
# note, can be either with or without Mongo::Code.new
javascript = "db.system.js.insert( { _id : 'combine', value : function( a ) " +
"{ return a.first + a.second; } } );"
MongoMapper.database.eval(javascript)
MongoMapper.database.eval('db.system.js.count();').should == 1
# just making sure we have the two documents
Test.count.should == 2
# use the function stored on the servera
# with or without Mongo::Code.new
Test.all(:conditions => {"$where" => Mongo::Code.new("combine(this) > 30")}).size.should == 1
min = 30
Test.all(:conditions => {"$where" => "combine(this) > #{min}"}).size.should == 1
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment