Level 1 support:
- Added PK factory support to the db class. Documented it in the README. - Mongo#db now takes an options hash (right now, for :strict and :pk) and passes it in to the DB constructor.
This commit is contained in:
parent
94f5214e45
commit
e0162aebb9
53
README.rdoc
53
README.rdoc
@ -63,7 +63,58 @@ read from Mongo will have their character encodings set to UTF-8.
|
||||
|
||||
When used with Ruby 1.8, the bytes in each string are written to and read from
|
||||
Mongo as-is. If the string is ASCII all is well, because ASCII is a subset of
|
||||
UTF-8. If the string is not ASCII then it may not be a well-formed UTF-8 string.
|
||||
UTF-8. If the string is not ASCII then it may not be a well-formed UTF-8
|
||||
string.
|
||||
|
||||
== The DB class
|
||||
|
||||
=== Primary Key Factories
|
||||
|
||||
A basic Mongo driver is not responsible for creating primary keys or knowing
|
||||
how to interpret them. You can tell the Ruby Mongo driver how to create
|
||||
primary keys by passing in the :pk option to the Mongo#db method.
|
||||
|
||||
include XGen::Mongo::Driver
|
||||
db = Mongo.new.db('dbname', :pk => MyPKFactory)
|
||||
|
||||
A primary key factory object must respond to :create_pk, which should take a
|
||||
hash and return a hash which merges the original hash with any primary key
|
||||
fields the factory wishes to inject. NOTE: if the object already has a primary
|
||||
key, the factory should not inject a new key; this means that the object is
|
||||
being used in a repsert but it already exists. The idea here is that when ever
|
||||
a record is inserted, the :pk object's +create_pk+ method will be called and
|
||||
the new hash returned will be inserted.
|
||||
|
||||
Here is a sample primary key factory, taken from the tests:
|
||||
|
||||
class TestPKFactory
|
||||
def create_pk(row)
|
||||
row['_id'] ||= XGen::Mongo::Driver::ObjectID.new
|
||||
row
|
||||
end
|
||||
end
|
||||
|
||||
A database's PK factory object may not be changed. Right now, it may only be
|
||||
specified when you obtain the db object.
|
||||
|
||||
=== Strict mode
|
||||
|
||||
Each database has an optional strict mode. If strict mode is on, then asking
|
||||
for a collection that does not exist will raise an error, as will asking to
|
||||
create a collection that already exists. Note that both these operations are
|
||||
completely harmless; strict mode is a programmer convenience only.
|
||||
|
||||
To turn on strict mode, either pass in :strict => true when obtaining a DB
|
||||
object or call the :strict= method:
|
||||
|
||||
db = XGen::Mongo::Driver::Mongo.new.db('dbname', :strict => true)
|
||||
# I'm feeling lax
|
||||
db.strict = false
|
||||
# No, I'm not!
|
||||
db.strict = true
|
||||
|
||||
The method DB#strict? returns the current value of that flag.
|
||||
|
||||
|
||||
= Testing
|
||||
|
||||
|
@ -59,17 +59,40 @@ module XGen
|
||||
# The database's socket. For internal (and Cursor) use only.
|
||||
attr_reader :socket
|
||||
|
||||
# A primary key factory object (or +nil+). See the README.doc file or
|
||||
# DB#new for details.
|
||||
attr_reader :pk_factory
|
||||
|
||||
# db_name :: The database name
|
||||
#
|
||||
# nodes :: An array of [host, port] pairs.
|
||||
#
|
||||
# options :: A hash of options.
|
||||
#
|
||||
# Options:
|
||||
#
|
||||
# :strict :: If true, collections must exist to be accessed and must
|
||||
# not exist to be created. See #collection and
|
||||
# #create_collection.
|
||||
#
|
||||
# :pk :: A primary key factory object that must respond to :create_pk,
|
||||
# which should take a hash and return a hash which merges the
|
||||
# original hash with any primary key fields the factory wishes
|
||||
# to inject. (NOTE: if the object already has a primary key,
|
||||
# the factory should not inject a new key; this means that the
|
||||
# object is being used in a repsert but it already exists.) The
|
||||
# idea here is that when ever a record is inserted, the :pk
|
||||
# object's +create_pk+ method will be called and the new hash
|
||||
# returned will be inserted.
|
||||
#
|
||||
# When a DB object first connects, it tries the first node. If that
|
||||
# fails, it keeps trying to connect to the remaining nodes until it
|
||||
# sucessfully connects.
|
||||
def initialize(db_name, nodes)
|
||||
def initialize(db_name, nodes, options={})
|
||||
raise "Invalid DB name" if !db_name || (db_name && db_name.length > 0 && db_name.include?("."))
|
||||
@name, @nodes = db_name, nodes
|
||||
@strict = false
|
||||
@strict = options[:strict]
|
||||
@pk_factory = options[:pk]
|
||||
@semaphore = Object.new
|
||||
@semaphore.extend Mutex_m
|
||||
connect_to_first_available_host
|
||||
@ -252,8 +275,8 @@ module XGen
|
||||
# applying +obj+ as an update. If no match, inserts (???). Normally
|
||||
# called by Collection#repsert.
|
||||
def repsert_in_db(collection_name, selector, obj)
|
||||
# TODO if PKInjector, inject
|
||||
@semaphore.synchronize {
|
||||
obj = @pk_factory.create_pk(obj) if @pk_factory
|
||||
send_to_db(UpdateMessage.new(@name, collection_name, selector, obj, true))
|
||||
obj
|
||||
}
|
||||
@ -325,7 +348,10 @@ module XGen
|
||||
# Collection#insert.
|
||||
def insert_into_db(collection_name, objects)
|
||||
@semaphore.synchronize {
|
||||
objects.each { |o| send_to_db(InsertMessage.new(@name, collection_name, o)) }
|
||||
objects.each { |o|
|
||||
o = @pk_factory.create_pk(o) if @pk_factory
|
||||
send_to_db(InsertMessage.new(@name, collection_name, o))
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -52,9 +52,10 @@ module XGen
|
||||
end
|
||||
end
|
||||
|
||||
# Return the XGen::Mongo::Driver::DB named +db_name+.
|
||||
def db(db_name)
|
||||
XGen::Mongo::Driver::DB.new(db_name, @nodes)
|
||||
# Return the XGen::Mongo::Driver::DB named +db_name+. See DB#new for
|
||||
# +options+.
|
||||
def db(db_name, options={})
|
||||
XGen::Mongo::Driver::DB.new(db_name, @nodes, options)
|
||||
end
|
||||
|
||||
# Returns a hash containing database names as keys and disk space for
|
||||
|
@ -2,6 +2,13 @@ $LOAD_PATH[0,0] = File.join(File.dirname(__FILE__), '..', 'lib')
|
||||
require 'mongo'
|
||||
require 'test/unit'
|
||||
|
||||
class TestPKFactory
|
||||
def create_pk(row)
|
||||
row['_id'] ||= XGen::Mongo::Driver::ObjectID.new
|
||||
row
|
||||
end
|
||||
end
|
||||
|
||||
# NOTE: assumes Mongo is running
|
||||
class DBTest < Test::Unit::TestCase
|
||||
|
||||
@ -48,4 +55,25 @@ class DBTest < Test::Unit::TestCase
|
||||
assert @db.connected?
|
||||
end
|
||||
|
||||
def test_pk_factory
|
||||
db = Mongo.new(@host, @port).db('ruby-mongo-test', :pk => TestPKFactory.new)
|
||||
coll = db.collection('test')
|
||||
coll.clear
|
||||
|
||||
coll.insert('name' => 'Fred')
|
||||
row = coll.find({'name' => 'Fred'}, :limit => 1).next_object
|
||||
assert_not_nil row
|
||||
assert_equal 'Fred', row['name']
|
||||
assert_kind_of XGen::Mongo::Driver::ObjectID, row['_id']
|
||||
|
||||
oid = XGen::Mongo::Driver::ObjectID.new
|
||||
coll.insert('_id' => oid, 'name' => 'Barney')
|
||||
row = coll.find({'name' => 'Barney'}, :limit => 1).next_object
|
||||
assert_not_nil row
|
||||
assert_equal 'Barney', row['name']
|
||||
assert_equal oid, row['_id']
|
||||
|
||||
coll.clear
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user