Index: TODO =================================================================== diff -u -N -ra6a6d9c14bfefba367b3147e05fbab4137f044ce -ra77e97b5d2b703b7c60a850b1f20f6c75e5029ac --- TODO (.../TODO) (revision a6a6d9c14bfefba367b3147e05fbab4137f044ce) +++ TODO (.../TODO) (revision a77e97b5d2b703b7c60a850b1f20f6c75e5029ac) @@ -4930,6 +4930,7 @@ - some c-code cleanup - tested with mongodb-c-driver 0.92.3 - added mongo::collection::stats +- added mongo::cursor::aggregate - extended regression test ======================================================================== Index: library/mongodb/mongoAPI.decls =================================================================== diff -u -N -ra6a6d9c14bfefba367b3147e05fbab4137f044ce -ra77e97b5d2b703b7c60a850b1f20f6c75e5029ac --- library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision a6a6d9c14bfefba367b3147e05fbab4137f044ce) +++ library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision a77e97b5d2b703b7c60a850b1f20f6c75e5029ac) @@ -85,6 +85,13 @@ # # Cursor # +cmd cursor::aggregate NsfMongoCursorAggregate { + {-argName "collection" -required 1 -type mongoc_collection_t} + {-argName "pipeline" -required 1 -type tclobj} + {-argName "options" -required 1 -type tclobj} + {-argName "-tailable" -required 0 -nrargs 0} + {-argName "-awaitdata" -required 0 -nrargs 0} +} cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "query" -required 1 -type tclobj} Index: library/mongodb/mongoAPI.h =================================================================== diff -u -N -ra6a6d9c14bfefba367b3147e05fbab4137f044ce -ra77e97b5d2b703b7c60a850b1f20f6c75e5029ac --- library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision a6a6d9c14bfefba367b3147e05fbab4137f044ce) +++ library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision a77e97b5d2b703b7c60a850b1f20f6c75e5029ac) @@ -85,7 +85,7 @@ /* just to define the symbol */ -static Nsf_methodDefinition method_definitions[27]; +static Nsf_methodDefinition method_definitions[28]; static CONST char *method_command_namespace_names[] = { "::mongo" @@ -101,6 +101,7 @@ static int NsfMongoCollectionStatsStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoCollectionUpdateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoConnectStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); +static int NsfMongoCursorAggregateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoCursorCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoCursorFindStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); static int NsfMongoCursorNextStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv []); @@ -128,6 +129,7 @@ static int NsfMongoCollectionStats(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *withOptions); static int NsfMongoCollectionUpdate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *cond, Tcl_Obj *values, int withUpsert, int withAll); static int NsfMongoConnect(Tcl_Interp *interp, CONST char *withUri); +static int NsfMongoCursorAggregate(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *pipeline, Tcl_Obj *options, int withTailable, int withAwaitdata); static int NsfMongoCursorClose(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr, Tcl_Obj *cursorObj); static int NsfMongoCursorFind(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *query, Tcl_Obj *withAtts, int withLimit, int withSkip, int withTailable, int withAwaitdata); static int NsfMongoCursorNext(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr); @@ -156,6 +158,7 @@ NsfMongoCollectionStatsIdx, NsfMongoCollectionUpdateIdx, NsfMongoConnectIdx, + NsfMongoCursorAggregateIdx, NsfMongoCursorCloseIdx, NsfMongoCursorFindIdx, NsfMongoCursorNextIdx, @@ -405,6 +408,29 @@ } static int +NsfMongoCursorAggregateStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { + ParseContext pc; + (void)clientData; + + if (likely(ArgumentParse(interp, objc, objv, NULL, objv[0], + method_definitions[NsfMongoCursorAggregateIdx].paramDefs, + method_definitions[NsfMongoCursorAggregateIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, + &pc) == TCL_OK)) { + mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; + Tcl_Obj *pipeline = (Tcl_Obj *)pc.clientData[1]; + Tcl_Obj *options = (Tcl_Obj *)pc.clientData[2]; + int withTailable = (int )PTR2INT(pc.clientData[3]); + int withAwaitdata = (int )PTR2INT(pc.clientData[4]); + + assert(pc.status == 0); + return NsfMongoCursorAggregate(interp, collectionPtr, pipeline, options, withTailable, withAwaitdata); + + } else { + return TCL_ERROR; + } +} + +static int NsfMongoCursorCloseStub(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { ParseContext pc; (void)clientData; @@ -709,7 +735,7 @@ } } -static Nsf_methodDefinition method_definitions[27] = { +static Nsf_methodDefinition method_definitions[28] = { {"::mongo::collection::close", NsfCollectionCloseStub, 1, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}} }, @@ -764,6 +790,13 @@ {"::mongo::connect", NsfMongoConnectStub, 1, { {"-uri", 0, 1, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, +{"::mongo::cursor::aggregate", NsfMongoCursorAggregateStub, 5, { + {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, + {"pipeline", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"options", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-tailable", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-awaitdata", 0, 0, Nsf_ConvertTo_String, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} +}, {"::mongo::cursor::close", NsfMongoCursorCloseStub, 1, { {"cursor", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_cursor_t",NULL,NULL,NULL,NULL,NULL}} }, Index: library/mongodb/nsfmongo.c =================================================================== diff -u -N -ra6a6d9c14bfefba367b3147e05fbab4137f044ce -ra77e97b5d2b703b7c60a850b1f20f6c75e5029ac --- library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision a6a6d9c14bfefba367b3147e05fbab4137f044ce) +++ library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision a77e97b5d2b703b7c60a850b1f20f6c75e5029ac) @@ -1010,6 +1010,80 @@ * Cursor interface ***********************************************************************/ /* +cmd cursor::aggregate NsfMongoCursorAggregate { + {-argName "collection" -required 1 -type mongoc_collection_t} + {-argName "pipeline" -required 1 -type tclobj} + {-argName "options" -required 1 -type tclobj} + {-argName "-tailable" -required 0 -nrargs 0} + {-argName "-awaitdata" -required 0 -nrargs 0} +} +*/ +static int +NsfMongoCursorAggregate(Tcl_Interp *interp, + mongoc_collection_t *collectionPtr, + Tcl_Obj *pipelineObj, + Tcl_Obj *optionsObj, + int withTailable, + int withAwaitdata) { + int objc1, objc2, result; + mongoc_query_flags_t queryFlags = 0; + Tcl_Obj **objv1, **objv2 = NULL; + mongoc_cursor_t *cursor; + bson_t pipeline, *pipelinePtr = &pipeline; + bson_t options, *optionsPtr = &options; + mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not used */ + + result = Tcl_ListObjGetElements(interp, pipelineObj, &objc1, &objv1); + if (result != TCL_OK || (objc1 % 3 != 0)) { + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(pipelineObj)); + } + result = Tcl_ListObjGetElements(interp, optionsObj, &objc2, &objv2); + if (result != TCL_OK || (objc2 % 3 != 0)) { + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(optionsObj)); + } + + BsonAppendObjv(interp, pipelinePtr, objc1, objv1); + BsonAppendObjv(interp, optionsPtr, objc2, objv2); + + /* + * The last field of mongo_find is options, semantics are described here + * http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPQUERY + */ + if (withTailable) { + queryFlags |= MONGOC_QUERY_TAILABLE_CURSOR; + } + if (withAwaitdata) { + queryFlags |= MONGOC_QUERY_AWAIT_DATA; + } + /* TODO: query flags: + MONGOC_QUERY_SLAVE_OK = 1 << 2, + MONGOC_QUERY_OPLOG_REPLAY = 1 << 3, + MONGOC_QUERY_NO_CURSOR_TIMEOUT = 1 << 4, + MONGOC_QUERY_EXHAUST = 1 << 6, + MONGOC_QUERY_PARTIAL = 1 << 7, + */ + cursor = mongoc_collection_aggregate(collectionPtr, queryFlags, + pipelinePtr, optionsPtr, + readPrefsPtr); + if (cursor) { + char buffer[80]; + if (Nsf_PointerAdd(interp, buffer, "mongoc_cursor_t", cursor) == TCL_OK) { + Tcl_SetObjResult(interp, Tcl_NewStringObj(buffer, -1)); + } else { + mongoc_cursor_destroy( cursor ); + result = TCL_ERROR; + } + } else { + Tcl_ResetResult(interp); + } + + bson_destroy( pipelinePtr ); + bson_destroy( optionsPtr ); + + return result; +} + +/* cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} {-argName "query" -required 1 -type tclobj} @@ -1046,8 +1120,6 @@ if (result != TCL_OK || (objc2 % 3 != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withAttsObj)); } - } else { - objc2 = 0; } BsonAppendObjv(interp, queryPtr, objc1, objv1);