From dcf90d4def6aa68082c1ec95f2699dfbbc8a1d2d Mon Sep 17 00:00:00 2001 From: Dwight Date: Thu, 29 Jan 2009 18:38:35 -0500 Subject: [PATCH] sort() for c++ client --- client/dbclient.cpp | 49 +++++++++++++++++++++------ client/dbclient.h | 58 +++++++++++++++++++++++--------- client/examples/authTest.cpp | 4 +-- client/examples/clientTest.cpp | 6 ++-- client/examples/first.cpp | 2 +- client/examples/second.cpp | 8 ++--- client/examples/whereExample.cpp | 8 ++--- db/db.vcproj | 4 +++ db/jsobj.h | 10 ++++-- tools/dump.cpp | 2 +- util/mmap_win.cpp | 12 +++---- 11 files changed, 112 insertions(+), 51 deletions(-) diff --git a/client/dbclient.cpp b/client/dbclient.cpp index ebcbb856c9b..910d6d1358c 100644 --- a/client/dbclient.cpp +++ b/client/dbclient.cpp @@ -28,6 +28,17 @@ namespace mongo { + Query& Query::sort(const BSONObj& s) { + BSONObjBuilder b; + if( s.hasElement("query") ) + b.appendElements(obj); + else + b.append("query", obj); + b.append("orderby", s); + obj = b.doneAndDecouple(); + return *this; + } + /* --- dbclientcommands --- */ inline bool DBClientWithCommands::isOk(const BSONObj& o) { @@ -190,6 +201,20 @@ namespace mongo { return eval(dbname, jscode, info, retValue); } + void testSort() { + DBClientConnection c; + string err; + if ( !c.connect("localhost", err) ) { + out() << "can't connect to server " << err << endl; + return; + } + + cout << "findOne returns:" << endl; + cout << c.findOne("test.foo", QUERY( "x" << 3 ) ).toString() << endl; + cout << c.findOne("test.foo", QUERY( "x" << 3 ).sort("name") ).toString() << endl; + + } + /* TODO: unit tests should run this? */ void testDbEval() { DBClientConnection c; @@ -230,7 +255,7 @@ namespace mongo { void testPaired(); int test2() { - testPaired(); + testSort(); return 0; } @@ -252,7 +277,7 @@ namespace mongo { return DBClientBase::auth(dbname, username, password.c_str(), errmsg, false); } - BSONObj DBClientBase::findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn, int queryOptions) { + BSONObj DBClientBase::findOne(const char *ns, Query query, BSONObj *fieldsToReturn, int queryOptions) { auto_ptr c = this->query(ns, query, 1, 0, fieldsToReturn, queryOptions); @@ -326,10 +351,10 @@ namespace mongo { } } - auto_ptr DBClientBase::query(const char *ns, BSONObj query, int nToReturn, + auto_ptr DBClientBase::query(const char *ns, Query query, int nToReturn, int nToSkip, BSONObj *fieldsToReturn, int queryOptions) { auto_ptr c( new DBClientCursor( this, - ns, query, nToReturn, nToSkip, + ns, query.obj, nToReturn, nToSkip, fieldsToReturn, queryOptions ) ); if ( c->init() ) return c; @@ -365,7 +390,7 @@ namespace mongo { say( toSend ); } - void DBClientBase::remove( const char * ns , BSONObj obj , bool justOne ) { + void DBClientBase::remove( const char * ns , Query obj , bool justOne ) { Message toSend; BufBuilder b; @@ -374,18 +399,18 @@ namespace mongo { b.append( ns ); int flags = 0; - if ( justOne || obj.hasField( "_id" ) ) + if ( justOne || obj.obj.hasField( "_id" ) ) flags |= 1; b.append( flags ); - obj.appendSelfToBufBuilder( b ); + obj.obj.appendSelfToBufBuilder( b ); toSend.setData( dbDelete , b.buf() , b.len() ); say( toSend ); } - void DBClientBase::update( const char * ns , BSONObj query , BSONObj obj , bool upsert ) { + void DBClientBase::update( const char * ns , Query query , BSONObj obj , bool upsert ) { BufBuilder b; b.append( (int)0 ); // reserverd @@ -393,7 +418,7 @@ namespace mongo { b.append( (int)upsert ); - query.appendSelfToBufBuilder( b ); + query.obj.appendSelfToBufBuilder( b ); obj.appendSelfToBufBuilder( b ); Message toSend; @@ -645,11 +670,13 @@ again: return ss.str(); } +#pragma warning(disable: 4355) DBClientPaired::DBClientPaired() : left(true, this), right(true, this) { master = NotSetL; } +#pragma warning(default: 4355) /* find which server, the left or right, is currently master mode */ void DBClientPaired::_checkMaster() { @@ -730,13 +757,13 @@ again: return true; } - auto_ptr DBClientPaired::query(const char *a, BSONObj b, int c, int d, + auto_ptr DBClientPaired::query(const char *a, Query b, int c, int d, BSONObj *e, int f) { return checkMaster().query(a,b,c,d,e,f); } - BSONObj DBClientPaired::findOne(const char *a, BSONObj b, BSONObj *c, int d) { + BSONObj DBClientPaired::findOne(const char *a, Query b, BSONObj *c, int d) { return checkMaster().findOne(a,b,c,d); } diff --git a/client/dbclient.h b/client/dbclient.h index 16096f6fb10..f252c458308 100644 --- a/client/dbclient.h +++ b/client/dbclient.h @@ -73,7 +73,33 @@ namespace mongo { } }; #pragma pack(pop) - + + /** Represents a query */ + class Query { + public: + BSONObj obj; + Query(const BSONObj& b) : obj(b) { } + + /** Add a sort (ORDER BY) criteria to the query expression. + @param sortPattern the sort order template. For example to order by name ascending, time descending: + { name : 1, ts : -1 } + i.e. + BSON( "name" << 1 << "ts" << -1 ) + or + fromjson(" \"name\" : 1, \"ts\" : -1 ") + */ + Query& sort(const BSONObj& sortPattern); + + /** Add a sort (ORDER BY) criteria to the query expression. + This version of sort() assumes you want to sort on a single field. + @asc = 1 for ascending order + asc = -1 for descending order + */ + Query& sort(const char *field, int asc = 1) { sort( BSON( field << asc ) ); return *this; } + }; + +#define QUERY(x) Query( BSON(x) ) + /** interface that handles communication with the db */ @@ -161,18 +187,18 @@ namespace mongo { */ class DBClientInterface : boost::noncopyable { public: - virtual auto_ptr query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + virtual auto_ptr query(const char *ns, Query query, int nToReturn = 0, int nToSkip = 0, BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; - virtual BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; + virtual BSONObj findOne(const char *ns, Query query, BSONObj *fieldsToReturn = 0, int queryOptions = 0) = 0; virtual void insert( const char * ns, BSONObj obj ) = 0; virtual void insert( const char * ns, const vector< BSONObj >& v ) = 0; - virtual void remove( const char * ns , BSONObj obj , bool justOne = 0 ) = 0; + virtual void remove( const char * ns , Query query, bool justOne = 0 ) = 0; - virtual void update( const char * ns , BSONObj query , BSONObj obj , bool upsert = 0 ) = 0; + virtual void update( const char * ns , Query query , BSONObj obj , bool upsert = 0 ) = 0; }; /** @@ -250,8 +276,8 @@ namespace mongo { BSONObj info; - runCommand( db.c_str() , BUILDOBJ( "deleteIndexes" << coll << "index" << "*" ) , info ); - return runCommand( db.c_str() , BUILDOBJ( "drop" << coll ) , info ); + runCommand( db.c_str() , BSON( "deleteIndexes" << coll << "index" << "*" ) , info ); + return runCommand( db.c_str() , BSON( "drop" << coll ) , info ); } /* Perform a repair and compaction of the specified database. May take a long time to run. Disk space @@ -362,14 +388,14 @@ namespace mongo { @return cursor. 0 if error (connection failure) @throws AssertionException */ - virtual auto_ptr query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + virtual auto_ptr query(const char *ns, Query query, int nToReturn = 0, int nToSkip = 0, BSONObj *fieldsToReturn = 0, int queryOptions = 0); /** @return a single object that matches the query. if none do, then the object is empty @throws AssertionException */ - virtual BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); + virtual BSONObj findOne(const char *ns, Query query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); /** insert an object into the database @@ -385,12 +411,12 @@ namespace mongo { remove matching objects from the database @param justOne if this true, then once a single match is found will stop */ - virtual void remove( const char * ns , BSONObj obj , bool justOne = 0 ); + virtual void remove( const char * ns , Query q , bool justOne = 0 ); /** updates objects matching query */ - virtual void update( const char * ns , BSONObj query , BSONObj obj , bool upsert = 0 ); + virtual void update( const char * ns , Query query , BSONObj obj , bool upsert = 0 ); /** if name isn't specified, it will be created from the keys (recommended) @@ -445,7 +471,7 @@ namespace mongo { /* overridden here to implement authCache for retries */ virtual bool auth(const char *dbname, const char *username, const char *pwd, string& errmsg, bool digestPassword = true); - virtual auto_ptr query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + virtual auto_ptr query(const char *ns, Query query, int nToReturn = 0, int nToSkip = 0, BSONObj *fieldsToReturn = 0, int queryOptions = 0) { checkConnection(); return DBClientBase::query( ns, query, nToReturn, nToSkip, fieldsToReturn, queryOptions ); @@ -514,12 +540,12 @@ namespace mongo { /* throws userassertion "no master found" */ virtual - auto_ptr query(const char *ns, BSONObj query, int nToReturn = 0, int nToSkip = 0, + auto_ptr query(const char *ns, Query query, int nToReturn = 0, int nToSkip = 0, BSONObj *fieldsToReturn = 0, int queryOptions = 0); /* throws userassertion "no master found" */ virtual - BSONObj findOne(const char *ns, BSONObj query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); + BSONObj findOne(const char *ns, Query query, BSONObj *fieldsToReturn = 0, int queryOptions = 0); // Not yet implemented virtual void insert( const char * ns , BSONObj obj ) { @@ -532,12 +558,12 @@ namespace mongo { } // Not yet implemented - virtual void remove( const char * ns , BSONObj obj , bool justOne = 0 ) { + virtual void remove( const char * ns , Query obj , bool justOne = 0 ) { assert( false ); } // Not yet implemented - virtual void update( const char * ns , BSONObj query , BSONObj obj , bool upsert = 0 ) { + virtual void update( const char * ns , Query query , BSONObj obj , bool upsert = 0 ) { assert( false ); } diff --git a/client/examples/authTest.cpp b/client/examples/authTest.cpp index 123039cbd95..50cef661cdd 100644 --- a/client/examples/authTest.cpp +++ b/client/examples/authTest.cpp @@ -2,7 +2,7 @@ #include -#include "mongo/client/dbclient.h" +#include "client/dbclient.h" using namespace mongo; @@ -19,7 +19,7 @@ int main() { conn.remove( "test.system.users" , emptyObj ); } - conn.insert( "test.system.users" , BUILDOBJ( "user" << "eliot" << "pwd" << conn.createPasswordDigest( "bar" ) ) ); + conn.insert( "test.system.users" , BSON( "user" << "eliot" << "pwd" << conn.createPasswordDigest( "bar" ) ) ); errmsg.clear(); bool ok = conn.auth( "test" , "eliot" , "bar" , errmsg ); diff --git a/client/examples/clientTest.cpp b/client/examples/clientTest.cpp index c625f9d8f35..7fa0b142af5 100644 --- a/client/examples/clientTest.cpp +++ b/client/examples/clientTest.cpp @@ -6,7 +6,7 @@ #include -#include "mongo/client/dbclient.h" +#include "client/dbclient.h" using namespace std; using namespace mongo; @@ -102,8 +102,8 @@ int main() { } { // ensure index - assert( conn.ensureIndex( ns , BUILDOBJ( "name" << 1 ) ) ); - assert( ! conn.ensureIndex( ns , BUILDOBJ( "name" << 1 ) ) ); + assert( conn.ensureIndex( ns , BSON( "name" << 1 ) ) ); + assert( ! conn.ensureIndex( ns , BSON( "name" << 1 ) ) ); } cout << "client test finished!" << endl; diff --git a/client/examples/first.cpp b/client/examples/first.cpp index 76ae0bd77d8..570eb1992f4 100644 --- a/client/examples/first.cpp +++ b/client/examples/first.cpp @@ -6,7 +6,7 @@ #include -#include "mongo/client/dbclient.h" +#include "client/dbclient.h" void insert( mongo::DBClientConnection & conn , const char * name , int num ) { mongo::BSONObjBuilder obj; diff --git a/client/examples/second.cpp b/client/examples/second.cpp index f5802eec30a..2afd5736f96 100644 --- a/client/examples/second.cpp +++ b/client/examples/second.cpp @@ -2,7 +2,7 @@ #include -#include "mongo/client/dbclient.h" +#include "client/dbclient.h" using namespace std; using namespace mongo; @@ -20,8 +20,8 @@ int main() { conn.remove( ns , emptyObj ); - conn.insert( ns , BUILDOBJ( "name" << "eliot" << "num" << 17 ) ); - conn.insert( ns , BUILDOBJ( "name" << "sara" << "num" << 24 ) ); + conn.insert( ns , BSON( "name" << "eliot" << "num" << 17 ) ); + conn.insert( ns , BSON( "name" << "sara" << "num" << 24 ) ); auto_ptr cursor = conn.query( ns , emptyObj ); cout << "using cursor" << endl; @@ -30,5 +30,5 @@ int main() { cout << "\t" << obj.jsonString() << endl; } - conn.ensureIndex( ns , BUILDOBJ( "name" << 1 << "num" << -1 ) ); + conn.ensureIndex( ns , BSON( "name" << 1 << "num" << -1 ) ); } diff --git a/client/examples/whereExample.cpp b/client/examples/whereExample.cpp index 7c73223ed69..ce2e1ff4741 100644 --- a/client/examples/whereExample.cpp +++ b/client/examples/whereExample.cpp @@ -2,7 +2,7 @@ #include -#include "mongo/client/dbclient.h" +#include "client/dbclient.h" using namespace std; using namespace mongo; @@ -20,8 +20,8 @@ int main() { conn.remove( ns , emptyObj ); - conn.insert( ns , BUILDOBJ( "name" << "eliot" << "num" << 17 ) ); - conn.insert( ns , BUILDOBJ( "name" << "sara" << "num" << 24 ) ); + conn.insert( ns , BSON( "name" << "eliot" << "num" << 17 ) ); + conn.insert( ns , BSON( "name" << "sara" << "num" << 24 ) ); auto_ptr cursor = conn.query( ns , emptyObj ); @@ -34,7 +34,7 @@ int main() { BSONObjBuilder query; - query.appendWhere( "this.name == name" , BUILDOBJ( "name" << "sara" ) ); + query.appendWhere( "this.name == name" , BSON( "name" << "sara" ) ); cursor = conn.query( ns , query.done() ); diff --git a/db/db.vcproj b/db/db.vcproj index 165e8798dbf..56a2bb90d85 100644 --- a/db/db.vcproj +++ b/db/db.vcproj @@ -340,6 +340,10 @@ RelativePath=".\matcher.cpp" > + + diff --git a/db/jsobj.h b/db/jsobj.h index 2f287e1437f..d5e181809ae 100644 --- a/db/jsobj.h +++ b/db/jsobj.h @@ -507,7 +507,7 @@ namespace mongo { } /** @return true if field exists in the object */ - bool hasElement(const char *name); + bool hasElement(const char *name) const; /** get the _id field from the object. assumes _id is the first element of the object -- this is done for performance. drivers should @@ -603,7 +603,11 @@ namespace mongo { typedef set< BSONObj, BSONObjCmpDefaultOrder > BSONObjSetDefaultOrder; -#define BUILDOBJ(x) ( BSONObjBuilder() << x ).doneAndDecouple() +/** Use BSON macro to build a BSONObj from a stream + e.g., + BSON( "name" << "joe" << "age" << 33 ) +*/ +#define BSON(x) (( BSONObjBuilder() << x ).doneAndDecouple()) class BSONObjBuilderValueStream { public: @@ -952,7 +956,7 @@ namespace mongo { return b.doneAndDecouple(); } - inline bool BSONObj::hasElement(const char *name) { + inline bool BSONObj::hasElement(const char *name) const { if ( !isEmpty() ) { BSONObjIterator it(*this); while ( it.more() ) { diff --git a/tools/dump.cpp b/tools/dump.cpp index 2293fa105da..c084db517e4 100644 --- a/tools/dump.cpp +++ b/tools/dump.cpp @@ -84,7 +84,7 @@ public: if ( db == "*" ){ cout << "all dbs" << endl; - BSONObj res = _conn.findOne( "admin.$cmd" , BUILDOBJ( "listDatabases" << 1 ) ); + BSONObj res = _conn.findOne( "admin.$cmd" , BSON( "listDatabases" << 1 ) ); BSONObj dbs = res.getField( "databases" ).embeddedObjectUserCheck(); set keys; dbs.getFieldNames( keys ); diff --git a/util/mmap_win.cpp b/util/mmap_win.cpp index e9633ac5b6f..46ab2d73022 100644 --- a/util/mmap_win.cpp +++ b/util/mmap_win.cpp @@ -17,11 +17,10 @@ */ -#if defined(_WIN32) - #include "stdafx.h" #include "mmap.h" -#include "windows.h" + +#if defined(_WIN32) namespace mongo { @@ -63,7 +62,7 @@ namespace mongo { out() << "CreateFile failed " << filename << endl; return 0; } - if ( mapped > 500000000 ) { + if ( mapped > 500000000 ) out() << "WARNING: too much mem mapped for win32" << endl; mapped += length; @@ -91,6 +90,7 @@ namespace mongo { #endif -int mmap_win_no_warnings; - +namespace mongo { + int mmap_win_no_warnings; +}