Browse files

Merge branch 'master' of http://github.com/marcesher/cfmongodb

  • Loading branch information...
2 parents 9b982fd + 07cbb14 commit 1d42e5b81a4ad804d61d71fcf97ffe93e0147ac4 bill shelton committed Jan 2, 2011
Showing with 158 additions and 17 deletions.
  1. +74 −12 core/Mongo.cfc
  2. +22 −3 core/MongoConfig.cfc
  3. +2 −1 examples/aggregation/load.cfm
  4. +1 −1 examples/gettingstarted.cfm
  5. +59 −0 test/MongoTest.cfc
View
86 core/Mongo.cfc
@@ -19,6 +19,8 @@
javaloaderFactory = createObject('component','cfmongodb.core.JavaloaderFactory').init();
mongoConfig = createObject('component','cfmongodb.core.MongoConfig').init(dbName="mongorocks", mongoFactory=javaloaderFactory);
mongo = createObject('component','cfmongodb.core.Mongo').init(mongoConfig);
+
+ Note that authentication credentials, if set in MongoConfig, will be used to authenticate against the database.
*
*/
function init(MongoConfig="#createObject('MongoConfig')#"){
@@ -34,10 +36,33 @@
}
mongoUtil = new MongoUtil(mongoFactory);
+
+ // Check for authentication, and if we have details set call it once on this database instance
+ if ( len(mongoConfig.getAuthDetails().username) and not authenticate(mongoConfig.getAuthDetails().username, mongoConfig.getAuthDetails().password) ) {
+ throw( message="Error authenticating MongoDB database." );
+ }
+
return this;
}
/**
+ * authenticates connection/db with given name and password
+
+ Typical usage:
+ mongoConfig.init(...);
+ mongoConfig.setAuthDetails( username, password );
+ mongo = new Mongo(mongoConfig);
+
+ If you set credentials to mongoConfig, Mongo.cfc will use those credentials to authenticate upon initialization.
+ If authentication fails, an error will be thrown
+ *
+ */
+ boolean function authenticate( string username, string password ){
+ return getMongoDB( variables.mongoConfig ).authenticate( arguments.username, arguments.password.toCharArray() );
+ }
+
+
+ /**
* Closes the underlying mongodb object. Once closed, you cannot perform additional mongo operations and you'll need to init a new mongo.
Best practice is to close mongo in your Application.cfc's onApplicationStop() method. Something like:
getBeanFactory().getBean("mongo").close();
@@ -58,6 +83,14 @@
}
/**
+ * Returns the last error for the current connection.
+ */
+ function getLastError()
+ {
+ return getMongoDB().getLastError();
+ }
+
+ /**
* For simple mongo _id searches, use findById(), like so:
byID = mongo.findById( url.personId, collection );
@@ -103,7 +136,17 @@
This function assumes you are using this to *apply* additional changes to the "found" document. If you wish to overwrite, pass overwriteExisting=true. One bristles at the thought
*/
- function findAndModify(struct query, struct fields={}, any sort={"_id"=1}, boolean remove=false, struct update, boolean returnNew=true, boolean upsert=false, boolean applySet=true, string collectionName, mongoConfig=""){
+ function findAndModify(struct query, struct fields, any sort, boolean remove=false, struct update, boolean returnNew=true, boolean upsert=false, boolean applySet=true, string collectionName, mongoConfig=""){
+ // Confirm our complex defaults exist; need this chunk of muck because CFBuilder 1 breaks with complex datatypes in defaults
+ local.argumentDefaults = {sort={"_id"=1},fields={}};
+ for(local.k in local.argumentDefaults)
+ {
+ if (!structKeyExists(arguments, local.k))
+ {
+ arguments[local.k] = local.argumentDefaults[local.k];
+ }
+ }
+
var collection = getMongoDBCollection(collectionName, mongoConfig);
//must apply $set, otherwise old struct is overwritten
if( applySet ){
@@ -138,7 +181,14 @@
See examples/aggregation/group.cfm for detail
*/
- function group( collectionName, keys, initial, reduce, query={}, keyf="", finalize="" ){
+ function group( collectionName, keys, initial, reduce, query, keyf="", finalize="" ){
+
+ if (!structKeyExists(arguments, 'query'))
+ {
+ arguments.query = {};
+ }
+
+
var collection = getMongoDBCollection(collectionName);
var dbCommand =
{ "group" =
@@ -156,14 +206,6 @@
}
var result = getMongoDB().command( mongoUtil.toMongo(dbCommand) );
return result["retval"];
- /*request.debug(result);
- return collection.group(
- mongoUtil.createOrderedDBObject(keys),
- mongoUtil.toMongo(query),
- mongoUtil.toMongo(initial),
- trim(reduce)
- );*/
-
}
/**
@@ -176,7 +218,21 @@
See examples/aggregation/mapReduce for detail
*/
- function mapReduce( collectionName, map, reduce, query={}, sort={}, limit="0", out="", keeptemp="false", finalize="", scope={}, verbose="true", outType="normal" ){
+ function mapReduce( collectionName, map, reduce, query, sort, limit="0", out="", keeptemp="false", finalize="", scope, verbose="true", outType="normal" ){
+
+ // Confirm our complex defaults exist; need this hunk of muck because CFBuilder 1 breaks with complex datatypes as defaults
+ local.argumentDefaults = {
+ query={}
+ ,sort={}
+ ,scope={}
+ };
+ for(local.k in local.argumentDefaults)
+ {
+ if (!structKeyExists(arguments, local.k))
+ {
+ arguments[local.k] = local.argumentDefaults[local.k];
+ }
+ }
var dbCommand = mongoUtil.createOrderedDBObject(
[
@@ -254,7 +310,13 @@
Pass upsert=true to create a document if no documents are found that match the query criteria
*/
- function update(doc, collectionName, query={}, upsert=false, multi=false, applySet=true, mongoConfig=""){
+ function update(doc, collectionName, query, upsert=false, multi=false, applySet=true, mongoConfig=""){
+
+ if (!structKeyExists(arguments, 'query'))
+ {
+ arguments.query = {};
+ }
+
var collection = getMongoDBCollection(collectionName, mongoConfig);
if( structIsEmpty(query) ){
View
25 core/MongoConfig.cfc
@@ -9,12 +9,20 @@
variables.conf = {};
+ /**
+ * Constructor
+ * @hosts Defaults to [{serverName='localhost',serverPort='27017'}]
+ */
+ public function init(Array hosts, dbName='default_db', MongoFactory="#createObject('DefaultFactory')#"){
+
+ if (!structKeyExists(arguments, 'hosts') || arrayIsEmpty(arguments.hosts)) {
+ arguments.hosts = [{serverName='localhost',serverPort='27017'}];
+ }
- public function init(Array hosts = [{serverName='localhost',serverPort='27017'}], dbName='default_db', MongoFactory="#createObject('DefaultFactory')#"){
variables.mongoFactory = arguments.mongoFactory;
establishHostInfo();
- variables.conf = { dbname = dbName, servers = mongoFactory.getObject('java.util.ArrayList').init() };
+ variables.conf = { dbname = dbName, servers = mongoFactory.getObject('java.util.ArrayList').init(), auth={username="",password=""} };
var item = "";
for(item in arguments.hosts){
@@ -35,13 +43,24 @@
public function removeAllServers(){
variables.conf.servers.clear();
+ return this;
+ }
+
+ public function setAuthDetails(username, password) {
+ structAppend(variables.conf.auth, arguments);
+ return this;
}
- public void function establishHostInfo(){
+ public struct function getAuthDetails() {
+ return variables.conf.auth;
+ }
+
+ public function establishHostInfo(){
// environment decisions can often be made from this information
var inetAddress = createObject( "java", "java.net.InetAddress");
variables.hostAddress = inetAddress.getLocalHost().getHostAddress();
variables.hostName = inetAddress.getLocalHost().getHostName();
+ return this;
}
/**
View
3 examples/aggregation/load.cfm
@@ -4,7 +4,8 @@
collection = "tasks";
total = mongo.query(collection).count();
-if(NOT total OR forceLoad){
+badRecords = mongo.query(collection).$exists("ADDEDTS",false).count();
+if(NOT total OR forceLoad OR badRecords){
mongo.remove({},collection);
nextNum = 1;
View
2 examples/gettingstarted.cfm
@@ -282,7 +282,7 @@ h2{
function showResult( searchResult, label ){
writeOutput("<h2>#label#</h2>");
- writeDump( var=searchResult.asArray(), label=label, expand="false" );
+ writeDump( var=searchResult.asArray(), label=label & '(Result from MongoDB)', expand="false" );
writeOutput( "<br>Total #label# in this result, accounting for skip and limit: " & searchResult.size() );
writeOutput( "<br>Total #label#, ignoring skip and limit: " & searchResult.totalCount() );
writeOutput( "<br>Query: " & searchResult.getQuery().toString() );
View
59 test/MongoTest.cfc
@@ -445,6 +445,65 @@ function newDBObject_should_create_correct_datatypes(){
}
+/**
+* Confirm getLastError works and mongo has not changed its response.
+*/
+function getLastError_should_return_error_when_expected()
+{
+ var jColl = mongo.getMongoDBCollection(col, mongoConfig);
+ var mongoUtil = mongo.getMongoUtil();
+
+ // Create people to steal an id from
+ createPeople();
+
+ // Get the result of the last activity from CreatePeople()
+ local.lastActivity = mongo.getLastError();
+
+ // Verify the structure returned by Mongo has not changed
+ var expected = listToArray('n,ok,err');
+ local.actualKeys = structKeyArray(local.lastActivity);
+ arraySort(local.actualKeys,'text');
+ arraySort(expected,'text');
+ assertEquals(
+ local.actualKeys
+ ,expected
+ ,'Mongo may have changed the getLastError() response.'
+ );
+
+ local.peeps = mongo.query(collectionName=col).search(limit="1").asArray();
+ assertFalse(
+ arrayIsEmpty(local.peeps)
+ ,'Some people should have been returned.'
+ );
+
+
+ // Let's duplicate the record.
+ local.person = local.peeps[1];
+ jColl.insert([mongoUtil.toMongo(local.person)]);
+
+ // Get the result of the last activity
+ local.lastActivity = mongo.getLastError();
+
+ // Confirm we did try to duplicate an id.
+ assert(
+ structKeyExists(local.lastActivity,'code')
+ ,'Mongo should be upset a record was duplicated. Check the test.'
+ );
+
+ // We now expect the error code to exist.
+ var expected = listToArray('n,ok,err,code');
+ local.actualKeys = structKeyArray(local.lastActivity);
+ arraySort(local.actualKeys,'text');
+ arraySort(expected,'text');
+ assertEquals(
+ local.actualKeys
+ ,expected
+ ,'Mongo may have changed the getLastError() response.'
+ );
+
+ return;
+}
+
</cfscript>
</cfcomponent>

0 comments on commit 1d42e5b

Please sign in to comment.