Index: library/mongodb/README =================================================================== diff -u -N -r4468c6949ccaca090619183f11a5b4a1988a5a1c -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/README (.../README) (revision 4468c6949ccaca090619183f11a5b4a1988a5a1c) +++ library/mongodb/README (.../README) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -8,8 +8,9 @@ The current version is tested with - Tcl 8.5 and Tcl 8.6 -- MongoDB v3.0.8 (released Dec 15, 2015) -- mongodb-c-driver 1.3.1 (released Jan 18, 2016) +- MongoDB v3.4.0 (released Nov 26, 2016) +- mongodb-c-driver 1.5.1 (released Dec 17, 2016) +- libbson 1.5.1 (released Dec 17, 2016) Follow the following steps to get MongoDB up and running and to compile the MongoDB driver for nx: @@ -75,7 +76,7 @@ check the content in MongoDB: % mongo - MongoDB shell version: 2.6.5 + MongoDB shell version: v3.4.0 connecting to: test > use tutorial switched to db tutorial Index: library/mongodb/mongoAPI.decls =================================================================== diff -u -N -re3e8f375df1313380cd13a6cb97028569f99d729 -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision e3e8f375df1313380cd13a6cb97028569f99d729) +++ library/mongodb/mongoAPI.decls (.../mongoAPI.decls) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -76,10 +76,8 @@ } cmd "collection::query" NsfMongoCollectionQuery { {-argName "collection" -required 1 -type mongoc_collection_t} - {-argName "query" -required 1 -type tclobj} - {-argName "-atts" -required 0 -nrargs 1 -type tclobj} - {-argName "-limit" -required 0 -type int32} - {-argName "-skip" -required 0 -type int32} + {-argName "filter" -required 1 -type tclobj} + {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } cmd "collection::stats" NsfMongoCollectionStats { {-argName "collection" -required 1 -type mongoc_collection_t} @@ -105,12 +103,8 @@ } cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} - {-argName "query" -required 1 -type tclobj} - {-argName "-atts" -required 0 -nrargs 1 -type tclobj} - {-argName "-limit" -required 0 -type int32} - {-argName "-skip" -required 0 -type int32} - {-argName "-tailable" -required 0 -nrargs 0} - {-argName "-awaitdata" -required 0 -nrargs 0} + {-argName "filter" -required 1 -type tclobj} + {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } cmd cursor::next NsfMongoCursorNext { {-argName "cursor" -required 1 -type mongoc_cursor_t} Index: library/mongodb/mongoAPI.h =================================================================== diff -u -N -raa5b3f4293624fedf641985718ab15c82f5daf78 -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision aa5b3f4293624fedf641985718ab15c82f5daf78) +++ library/mongodb/mongoAPI.h (.../mongoAPI.h) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -165,7 +165,7 @@ NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionInsert(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *values) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); -static int NsfMongoCollectionQuery(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *query, Tcl_Obj *withAtts, int withLimit, int withSkip) +static int NsfMongoCollectionQuery(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filter, Tcl_Obj *withOpts) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCollectionStats(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *withOptions) NSF_nonnull(1) NSF_nonnull(2); @@ -177,7 +177,7 @@ NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3) NSF_nonnull(4); static int NsfMongoCursorClose(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr, Tcl_Obj *cursorObj) NSF_nonnull(1) NSF_nonnull(2); -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 NsfMongoCursorFind(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, Tcl_Obj *filter, Tcl_Obj *withOpts) NSF_nonnull(1) NSF_nonnull(2) NSF_nonnull(3); static int NsfMongoCursorNext(Tcl_Interp *interp, mongoc_cursor_t *cursorPtr) NSF_nonnull(1) NSF_nonnull(2); @@ -408,13 +408,11 @@ method_definitions[NsfMongoCollectionQueryIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; - Tcl_Obj *query = (Tcl_Obj *)pc.clientData[1]; - Tcl_Obj *withAtts = (Tcl_Obj *)pc.clientData[2]; - int withLimit = (int )PTR2INT(pc.clientData[3]); - int withSkip = (int )PTR2INT(pc.clientData[4]); + Tcl_Obj *filter = (Tcl_Obj *)pc.clientData[1]; + Tcl_Obj *withOpts = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); - return NsfMongoCollectionQuery(interp, collectionPtr, query, withAtts, withLimit, withSkip); + return NsfMongoCollectionQuery(interp, collectionPtr, filter, withOpts); } else { @@ -541,15 +539,11 @@ method_definitions[NsfMongoCursorFindIdx].nrParameters, 0, NSF_ARGPARSE_BUILTIN, &pc) == TCL_OK)) { mongoc_collection_t *collectionPtr = (mongoc_collection_t *)pc.clientData[0]; - Tcl_Obj *query = (Tcl_Obj *)pc.clientData[1]; - Tcl_Obj *withAtts = (Tcl_Obj *)pc.clientData[2]; - int withLimit = (int )PTR2INT(pc.clientData[3]); - int withSkip = (int )PTR2INT(pc.clientData[4]); - int withTailable = (int )PTR2INT(pc.clientData[5]); - int withAwaitdata = (int )PTR2INT(pc.clientData[6]); + Tcl_Obj *filter = (Tcl_Obj *)pc.clientData[1]; + Tcl_Obj *withOpts = (Tcl_Obj *)pc.clientData[2]; assert(pc.status == 0); - return NsfMongoCursorFind(interp, collectionPtr, query, withAtts, withLimit, withSkip, withTailable, withAwaitdata); + return NsfMongoCursorFind(interp, collectionPtr, filter, withOpts); } else { @@ -917,12 +911,10 @@ {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, {"values", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, -{"::mongo::collection::query", NsfMongoCollectionQueryStub, 5, { +{"::mongo::collection::query", NsfMongoCollectionQueryStub, 3, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, - {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, - {"-atts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, - {"-limit", 0, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}, - {"-skip", 0, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}} + {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-opts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::collection::stats", NsfMongoCollectionStatsStub, 2, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, @@ -948,14 +940,10 @@ {"::mongo::cursor::close", NsfMongoCursorCloseStub, 1, { {"cursor", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_cursor_t",NULL,NULL,NULL,NULL,NULL}} }, -{"::mongo::cursor::find", NsfMongoCursorFindStub, 7, { +{"::mongo::cursor::find", NsfMongoCursorFindStub, 3, { {"collection", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Pointer, NULL,NULL,"mongoc_collection_t",NULL,NULL,NULL,NULL,NULL}, - {"query", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, - {"-atts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, - {"-limit", 0, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",NULL,NULL,NULL,NULL,NULL}, - {"-skip", 0, 1, Nsf_ConvertTo_Int32, NULL,NULL,"int32",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}} + {"filter", NSF_ARG_REQUIRED, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}, + {"-opts", 0, 1, Nsf_ConvertTo_Tclobj, NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}} }, {"::mongo::cursor::next", NsfMongoCursorNextStub, 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 -rebb54b968b8019b826af792d34a760d8a916ab49 -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision ebb54b968b8019b826af792d34a760d8a916ab49) +++ library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -48,6 +48,7 @@ NSF_BSON_INT32, NSF_BSON_INT64, NSF_BSON_DATE_TIME, + NSF_BSON_DECIMAL128, NSF_BSON_DOCUMENT, NSF_BSON_DOUBLE, NSF_BSON_MINKEY, @@ -67,6 +68,7 @@ "int32", "int64", "datetime", + "decimal128", "document", "double", "minkey", @@ -176,18 +178,19 @@ *---------------------------------------------------------------------- */ Tcl_Obj * -BsonToList(Tcl_Interp *interp, const bson_t *data , int depth) { +BsonToList(Tcl_Interp *interp, const bson_t *data , int depth) +{ bson_iter_t i; - char oidhex[25]; - Tcl_Obj *resultObj, *elemObj; + char oidhex[25]; + Tcl_Obj *resultObj, *elemObj; bson_iter_init( &i , data ); resultObj = Tcl_NewListObj(0, NULL); while ( bson_iter_next( &i ) ){ - bson_type_t t = bson_iter_type( &i ); + bson_type_t t = bson_iter_type( &i ); nsfMongoTypes tag; - const char *key; + const char *key; if ( t == 0 ) break; @@ -202,6 +205,7 @@ case BSON_TYPE_BOOL: tag = NSF_BSON_BOOL; elemObj = Tcl_NewBooleanObj(bson_iter_bool( &i )); break; case BSON_TYPE_REGEX: { const char *options = NULL, *regex = NULL; + tag = NSF_BSON_REGEX; regex = bson_iter_regex( &i, &options ); elemObj = Tcl_NewListObj(0, NULL); @@ -210,8 +214,9 @@ break; } case BSON_TYPE_UTF8: { - uint32_t utf8_len; + uint32_t utf8_len; const char *string = bson_iter_utf8( &i, &utf8_len); + /*fprintf(stderr, "append UTF8: <%s> %d\n", string, utf8_len);*/ tag = NSF_BSON_STRING; elemObj = Tcl_NewStringObj(string, (int)utf8_len); break; @@ -227,6 +232,7 @@ } case BSON_TYPE_TIMESTAMP: { uint32_t timestamp, increment; + tag = NSF_BSON_TIMESTAMP; bson_iter_timestamp( &i, ×tamp, &increment ); elemObj = Tcl_NewListObj(0, NULL); @@ -236,8 +242,9 @@ } case BSON_TYPE_DOCUMENT: { const uint8_t *docbuf = NULL; - uint32_t doclen = 0; - bson_t b; + uint32_t doclen = 0; + bson_t b; + tag = NSF_BSON_DOCUMENT; bson_iter_document (&i, &doclen, &docbuf); bson_init_static(&b, docbuf, doclen); @@ -246,14 +253,26 @@ } case BSON_TYPE_ARRAY: { const uint8_t *docbuf = NULL; - uint32_t doclen = 0; - bson_t b; + uint32_t doclen = 0; + bson_t b; + tag = NSF_BSON_ARRAY; bson_iter_array(&i, &doclen, &docbuf); bson_init_static (&b, docbuf, doclen); elemObj = BsonToList(interp, &b , depth + 1 ); break; } + case BSON_TYPE_DECIMAL128: { + bson_decimal128_t decimal128; + char string[BSON_DECIMAL128_STRING]; + + tag = NSF_BSON_DECIMAL128; + bson_iter_decimal128( &i, &decimal128); + bson_decimal128_to_string (&decimal128, string); + elemObj = Tcl_NewStringObj(string, -1); + + break; + } default: tag = NSF_BSON_UNKNOWN; elemObj = Tcl_NewStringObj("", 0); @@ -287,7 +306,8 @@ *---------------------------------------------------------------------- */ bson_type_t -BsonTagToType(Tcl_Interp *interp, CONST char *tag) { +BsonTagToType(Tcl_Interp *interp, CONST char *tag) +{ char firstChar = *tag; switch (firstChar) { @@ -457,7 +477,13 @@ } break; } + case BSON_TYPE_DECIMAL128: { + bson_decimal128_t decimal128; + bson_decimal128_from_string (ObjStr(value), &decimal128); + bson_append_decimal128(bbPtr, name, keyLength, &decimal128); + break; + } case BSON_TYPE_BINARY: case BSON_TYPE_DBPOINTER: case BSON_TYPE_CODE: @@ -929,63 +955,56 @@ /* cmd collection::query NsfMongoCollectionQuery { {-argName "collection" -required 1 -type mongoc_collection_t} - {-argName "query" -required 1 -type tclobj} - {-argName "-atts" -required 0 -nrargs 1 -type tclobj} - {-argName "-limit" -required 0 -type int32} - {-argName "-skip" -required 0 -type int32} + {-argName "filter" -required 1 -type tclobj} + {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } */ static int NsfMongoCollectionQuery(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, - Tcl_Obj *queryObj, Tcl_Obj *withAttsObj, - int withLimit, int withSkip) { - int objc1, objc2 = 0, result; - Tcl_Obj **objv1, **objv2 = NULL, *resultObj; - mongoc_cursor_t *cursor; - bson_t query, *queryPtr = &query; - bson_t atts, *attsPtr = &atts; - const bson_t *nextPtr; - mongoc_query_flags_t queryFlags = 0; /* TODO: not handled */ - mongoc_read_prefs_t *readPrefs = NULL; /* TODO: not handled */ + Tcl_Obj *filterObj, Tcl_Obj *withOptsObj) +{ + int objc1, objc2 = 0, result; + Tcl_Obj **objv1, **objv2 = NULL, *resultObj; + mongoc_cursor_t *cursor; + bson_t filter, *const filterPtr = &filter; + bson_t opts, *const optsPtr = &opts; + const bson_t *nextPtr; + mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not handled */ /*fprintf(stderr, "NsfMongoQuery: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ - result = Tcl_ListObjGetElements(interp, queryObj, &objc1, &objv1); + result = Tcl_ListObjGetElements(interp, filterObj, &objc1, &objv1); if (result != TCL_OK || ((objc1 % 3) != 0)) { - return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } - if (withAttsObj != NULL) { - result = Tcl_ListObjGetElements(interp, withAttsObj, &objc2, &objv2); + if (withOptsObj != NULL) { + result = Tcl_ListObjGetElements(interp, withOptsObj, &objc2, &objv2); if (result != TCL_OK || ((objc2 % 3) != 0)) { - return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withAttsObj)); + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withOptsObj)); } } else { objc2 = 0; } - /* fprintf(stderr, "query # %d, atts # %d\n", objc1, objc2); */ - BsonAppendObjv(interp, queryPtr, objc1, objv1); - BsonAppendObjv(interp, attsPtr, objc2, objv2); + BsonAppendObjv(interp, filterPtr, objc1, objv1); + BsonAppendObjv(interp, optsPtr, objc2, objv2); resultObj = Tcl_NewListObj(0, NULL); - /* - * The last field of mongo_find is options, semantics are described here - * http://www.mongodb.org/display/DOCS/Mongo+Wire+Protocol#MongoWireProtocol-OPQUERY - */ - cursor = mongoc_collection_find( collectionPtr, queryFlags, - (uint32_t)withSkip, (uint32_t)withLimit, 0 /* batch_size */, - queryPtr, attsPtr, readPrefs); + cursor = mongoc_collection_find_with_opts( collectionPtr, + filterPtr, + optsPtr, + readPrefsPtr); while( mongoc_cursor_next( cursor, &nextPtr ) == 1 ) { Tcl_ListObjAppendElement(interp, resultObj, BsonToList(interp, nextPtr, 0)); } mongoc_cursor_destroy( cursor ); - bson_destroy( queryPtr ); - bson_destroy( attsPtr ); + bson_destroy( filterPtr ); + bson_destroy( optsPtr ); Tcl_SetObjResult(interp, resultObj); @@ -1100,7 +1119,8 @@ Tcl_Obj *pipelineObj, Tcl_Obj *optionsObj, int withTailable, - int withAwaitdata) { + int withAwaitdata) +{ int objc1, objc2, result; mongoc_query_flags_t queryFlags = 0; Tcl_Obj **objv1, **objv2 = NULL; @@ -1162,65 +1182,45 @@ /* cmd cursor::find NsfMongoCursorFind { {-argName "collection" -required 1 -type mongoc_collection_t} - {-argName "query" -required 1 -type tclobj} - {-argName "-atts" -required 0 -nrargs 1 -type tclobj} - {-argName "-limit" -required 0 -type int32} - {-argName "-skip" -required 0 -type int32} - {-argName "-tailable" -required 0 -nrargs 0} - {-argName "-awaitdata" -required 0 -nrargs 0} + {-argName "filter" -required 1 -type tclobj} + {-argName "-opts" -required 0 -nrargs 1 -type tclobj} } */ static int NsfMongoCursorFind(Tcl_Interp *interp, mongoc_collection_t *collectionPtr, - Tcl_Obj *queryObj, Tcl_Obj *withAttsObj, - int withLimit, int withSkip, - int withTailable, int withAwaitdata) { - int objc1, objc2 = 0, result; - mongoc_query_flags_t queryFlags = 0; - Tcl_Obj **objv1, **objv2 = NULL; - mongoc_cursor_t *cursor; - bson_t query, *queryPtr = &query; - bson_t atts, *attsPtr = &atts; + Tcl_Obj *filterObj, + Tcl_Obj *withOptsObj) +{ + int objc1, objc2 = 0, result; + Tcl_Obj **objv1, **objv2 = NULL; + mongoc_cursor_t *cursor; + bson_t filter, *filterPtr = &filter; + bson_t opts, *optsPtr = &opts; mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not used */ /*fprintf(stderr, "NsfMongoQuery: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ - result = Tcl_ListObjGetElements(interp, queryObj, &objc1, &objv1); + result = Tcl_ListObjGetElements(interp, filterObj, &objc1, &objv1); if (result != TCL_OK || ((objc1 % 3) != 0)) { - return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } - if (withAttsObj != NULL) { - result = Tcl_ListObjGetElements(interp, withAttsObj, &objc2, &objv2); + if (withOptsObj != NULL) { + result = Tcl_ListObjGetElements(interp, withOptsObj, &objc2, &objv2); if (result != TCL_OK || ((objc2 % 3) != 0)) { - return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withAttsObj)); + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(withOptsObj)); } } - BsonAppendObjv(interp, queryPtr, objc1, objv1); - BsonAppendObjv(interp, attsPtr, objc2, objv2); + BsonAppendObjv(interp, filterPtr, objc1, objv1); + BsonAppendObjv(interp, optsPtr, 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 != 0) { - queryFlags |= MONGOC_QUERY_TAILABLE_CURSOR; - } - if (withAwaitdata != 0) { - 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_find(collectionPtr, queryFlags, - (uint32_t)withSkip, (uint32_t)withLimit, 0 /*TODO missing batch_size*/, - queryPtr, attsPtr, readPrefsPtr); + cursor = mongoc_collection_find_with_opts( collectionPtr, + filterPtr, + optsPtr, + readPrefsPtr); + if (cursor != NULL) { char buffer[80]; if (Nsf_PointerAdd(interp, buffer, "mongoc_cursor_t", cursor) == TCL_OK) { @@ -1233,8 +1233,8 @@ Tcl_ResetResult(interp); } - bson_destroy( queryPtr ); - bson_destroy( attsPtr ); + bson_destroy( filterPtr ); + bson_destroy( optsPtr ); return result; } @@ -1429,46 +1429,55 @@ static int NsfMongoGridFileDelete(Tcl_Interp *interp, mongoc_gridfs_t *gridfsPtr, - Tcl_Obj *queryObj) { - bson_t query, *queryPtr = &query; - mongoc_cursor_t *files; - const bson_t *nextPtr; - bson_iter_t it; - Tcl_Obj **objv; - int objc, result; + Tcl_Obj *queryObj) +{ + bson_t query, *queryPtr = &query; + mongoc_cursor_t *files; + const bson_t *nextPtr; + bson_iter_t it; + Tcl_Obj **objv; + int objc, result; + mongoc_read_prefs_t *readPrefsPtr = NULL; /* TODO: not handled */ result = Tcl_ListObjGetElements(interp, queryObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); } BsonAppendObjv(interp, queryPtr, objc, objv); - files = mongoc_collection_find( mongoc_gridfs_get_files(gridfsPtr), 0, - 0, 0, 0 /* batch_size */, - queryPtr, NULL, NULL); + files = mongoc_collection_find_with_opts( mongoc_gridfs_get_files(gridfsPtr), + queryPtr, NULL, readPrefsPtr); bson_destroy(queryPtr); - /* files should be a valid cursor even if the file doesn't exist */ + /* + * Files should be a valid cursor even if the file doesn't exist. + */ if ( files == NULL ) { return NsfPrintError(interp, "gridfs::remove_file: invalid cursor for files"); } - /* Remove each file and it's chunks from files named filename */ + /* + * Remove each file and it's chunks from files named filename. + */ while (mongoc_cursor_next(files, &nextPtr)) { - bson_t bson, *bsonPtr = &bson; + bson_t bson, *bsonPtr = &bson; bson_error_t bsonError; - bson_oid_t id; + bson_oid_t id; bson_iter_init_find(&it, nextPtr, "_id"); id = *bson_iter_oid(&it); - /* Remove the file with the specified id */ + /* + * Remove the file with the specified id. + */ bson_init(bsonPtr); bson_append_oid(bsonPtr, "_id", 3, &id); mongoc_collection_remove(mongoc_gridfs_get_files(gridfsPtr), 0, bsonPtr, NULL, &bsonError); bson_destroy(bsonPtr); - /* Remove all chunks from the file with the specified id */ + /* + * Remove all chunks from the file with the specified id. + */ bson_init(bsonPtr); bson_append_oid(bsonPtr, "files_id", 8, &id); mongoc_collection_remove(mongoc_gridfs_get_chunks(gridfsPtr), 0, bsonPtr, NULL, &bsonError); @@ -1482,30 +1491,30 @@ /* cmd gridfile::open NsfMongoGridFileOpen { {-argName "gfs" -required 1 -type mongoc_gridfs_t} - {-argName "query" -required 1 -type tclobj} + {-argName "filter" -required 1 -type tclobj} } */ static int NsfMongoGridFileOpen(Tcl_Interp *interp, mongoc_gridfs_t *gridfsPtr, - Tcl_Obj *queryObj) { + Tcl_Obj *filterObj) { mongoc_gridfs_file_t* gridFilePtr; bson_error_t bsonError; int result, objc; - bson_t query, *queryPtr = &query; + bson_t filter, *filterPtr = &filter; Tcl_Obj **objv; - /*fprintf(stderr, "NsfMongoQuery: namespace %s withLimit %d withSkip %d\n", + /*fprintf(stderr, "NsfMongoFilter: namespace %s withLimit %d withSkip %d\n", namespace, withLimit, withSkip);*/ - result = Tcl_ListObjGetElements(interp, queryObj, &objc, &objv); + result = Tcl_ListObjGetElements(interp, filterObj, &objc, &objv); if (result != TCL_OK || ((objc % 3) != 0)) { - return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(queryObj)); + return NsfPrintError(interp, "%s: must contain a multiple of 3 elements", ObjStr(filterObj)); } - BsonAppendObjv(interp, queryPtr, objc, objv); + BsonAppendObjv(interp, filterPtr, objc, objv); - gridFilePtr = mongoc_gridfs_find_one(gridfsPtr, queryPtr, &bsonError); + gridFilePtr = mongoc_gridfs_find_one_with_opts(gridfsPtr, filterPtr, NULL, &bsonError); if (gridFilePtr != NULL) { char buffer[80]; @@ -1520,7 +1529,7 @@ Tcl_ResetResult(interp); } - bson_destroy(queryPtr); + bson_destroy(filterPtr); return result; } @@ -1644,7 +1653,7 @@ * We can't reliably call NsfLog. */ - /*fprintf(stderr, "+++ Nsfmongo_ThreadExit\n");*/ + fprintf(stderr, "+++ Nsfmongo_ThreadExit\n"); #if defined(USE_CLIENT_POOL) NsfMutexLock(&poolMutex); @@ -1672,7 +1681,7 @@ * NsfLog(interp,NSF_LOG_NOTICE, "Nsfmongo Exit"); */ - /*fprintf(stderr, "+++ Nsfmongo_Exit\n");*/ + fprintf(stderr, "+++ Nsfmongo_Exit\n"); #if defined(TCL_THREADS) Tcl_DeleteThreadExitHandler(Nsfmongo_ThreadExit, clientData); @@ -1724,7 +1733,7 @@ #endif /* - * Register global mongo tcl_objs + * Register global mongo tcl_objs. */ NsfMutexLock(&initMutex); if (NsfMongoGlobalObjs == NULL) { @@ -1740,7 +1749,7 @@ Nsf_CmdDefinitionRegister(interp, method_definitions); /* - * register the pointer converter + * Register the pointer converter. */ Nsf_PointerTypeRegister(interp, "mongoc_client_t", &mongoClientCount); Nsf_PointerTypeRegister(interp, "mongoc_collection_t", &mongoCollectionCount); @@ -1752,7 +1761,9 @@ Tcl_CreateNamespace(interp, method_command_namespace_names[i], 0, (Tcl_NamespaceDeleteProc *)NULL); } - /* create all method commands (will use the namespaces above) */ + /* + * Create all method commands (will use the namespaces above) + */ for (i=0; i < nr_elements(method_definitions)-1; i++) { Tcl_CreateObjCommand(interp, method_definitions[i].methodName, method_definitions[i].proc, 0, 0); } Index: library/mongodb/nx-mongo.tcl =================================================================== diff -u -N -r0f881e4bc45e927c8d84c1b1b468ef7537cb9b03 -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/nx-mongo.tcl (.../nx-mongo.tcl) (revision 0f881e4bc45e927c8d84c1b1b468ef7537cb9b03) +++ library/mongodb/nx-mongo.tcl (.../nx-mongo.tcl) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -434,10 +434,10 @@ # # For interaction with bson structures, we provide on the class # level "bson cond" (a small dsl for a more convenient syntax in - # bson queries), "bson query" (combining conditions with - # ordering), "bson atts (a simplifed property selection) and - # "bson parameter" which translates from a bson structure (tuple) - # into a dashed parameter list used in object creation. + # bson queries), "bson opts" (options like e.g. ordering), "bson + # atts (a simplifed property selection) and "bson parameter" which + # translates from a bson structure (tuple) into a dashed parameter + # list used in object creation. # :method "bson cond" {cond} { @@ -461,23 +461,32 @@ return $bson } - :method "bson query" {{-cond ""} {-orderby ""}} { - #puts "bson query -cond <$cond> -orderby <$orderby>" - set bson [:bson cond $cond] - set result [list \$query document $bson] - - if {[llength $orderby] > 0} { - set bson [list] - foreach attspec $orderby { - lassign $attspec att direction - lappend bson $att int [expr {$direction eq "desc" ? -1 : 1}] - } - lappend result \$orderby document $bson + :method "bson opts" {{-orderby ""} {-atts ""} -limit:integer -skip:integer} { + set result "" + if {$atts ne ""} { + lappend result projection document [:bson atts $atts] } - #puts "bson query -cond <$cond> -orderby <$orderby> => $result" + if {[info exists limit]} { + lappend result limit int64 $limit + } + if {[info exists skip]} { + lappend result skip int64 $skip + } + if {$orderby ne ""} { + lappend result sort document [:bson orderby $orderby] + } return $result } + :method "bson orderby" {orderby} { + set bson [list] + foreach attspec $orderby { + lassign $attspec att direction + lappend bson $att int [expr {$direction eq "desc" ? -1 : 1}] + } + return $bson + } + :method "bson atts" {atts} { set result {} foreach {att value} $atts { @@ -662,9 +671,9 @@ {-orderby ""} } { set tuple [lindex [::nx::mongo::db query ${:mongo_ns} \ - [:bson query -cond $cond -orderby $orderby] \ - -atts [:bson atts $atts] \ - -limit 1] 0] + [:bson cond $cond] \ + -opts [:bson opts -atts $atts -limit 1 -orderby $orderby] \ + ] 0] if {$tuple eq ""} { return "" } @@ -676,17 +685,16 @@ {-atts ""} {-cond ""} {-orderby ""} - {-limit} - {-skip} + {-limit:integer} + {-skip:integer} } { set result [list] set opts [list] if {[info exists limit]} {lappend opts -limit $limit} if {[info exists skip]} {lappend opts -skip $skip} set fetched [::nx::mongo::db query ${:mongo_ns} \ - [:bson query -cond $cond -orderby $orderby] \ - -atts [:bson atts $atts] \ - {*}$opts] + [:bson cond $cond] \ + -opts [:bson opts -orderby $orderby -atts $atts {*}$opts] ] foreach tuple $fetched { lappend result [:bson create $tuple] @@ -706,9 +714,8 @@ if {[info exists limit]} {lappend opts -limit $limit} if {[info exists skip]} {lappend opts -skip $skip} set fetched [::nx::mongo::db query ${:mongo_ns} \ - [:bson query -cond $cond -orderby $orderby] \ - -atts [:bson atts $atts] \ - {*}$opts] + [:bson cond $cond] \ + -opts [:bson opts -orderby $orderby -atts $atts {*}$opts] ] set tuples [list] foreach tuple $fetched { lappend tuples "\{[:bson pp -indent 4 $tuple]\n\}" Index: library/mongodb/tests/nsf-gridfs.test =================================================================== diff -u -N -rcef3de5c4f65e767d0c66389bacc77bc3c2e5a68 -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/tests/nsf-gridfs.test (.../nsf-gridfs.test) (revision cef3de5c4f65e767d0c66389bacc77bc3c2e5a68) +++ library/mongodb/tests/nsf-gridfs.test (.../nsf-gridfs.test) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -91,8 +91,8 @@ # Get the file named README from the gridfs via plain query interface # ? {set files [::mongo::collection::query $mongoColl \ - [list \$query document {filename string README}] \ - -limit 1] + {filename string README} \ + -opts { limit int64 1 }] llength [lindex $files 0] } 18 Index: library/mongodb/tests/nsf-mongo.test =================================================================== diff -u -N -r4dccd3ff7bcf142a60a2c56454411613ec50077e -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/tests/nsf-mongo.test (.../nsf-mongo.test) (revision 4dccd3ff7bcf142a60a2c56454411613ec50077e) +++ library/mongodb/tests/nsf-mongo.test (.../nsf-mongo.test) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -3,7 +3,54 @@ # This is a sample test set using the low-level (pure tcl) interface # for inserting and querying tuples into MongoDB. # +# Main differences in the query interface due to changes in the +# upstream c-driver interface between the interface in nsf 2.0.0 (old) +# and 2.1.0 (new): +# +# Simple Query: +# old [::mongo::collection::query $mongoColl [list \$query document {projects string nsf}]] +# new [::mongo::collection::query $mongoColl {projects string nsf}] +# +# old [::mongo::collection::query $mongoColl [list \$query document {age document {$gt int 30}}]] +# new [::mongo::collection::query $mongoColl {age document {$gt int 30}}] +# +# Sort: +# old [::mongo::collection::query $mongoColl \ +# [list \$query document {projects string nsf} \$orderby document {name int -1}]] +# new [::mongo::collection::query $mongoColl \ +# {projects string nsf} \ +# -opts {sort document {name int -1}}] +# Projection: +# old [::mongo::collection::query $mongoColl \ +# {$query document {age document {$gt int 30}}} \ +# -atts {name int 1 age int 1}] +# new [::mongo::collection::query $mongoColl \ +# {age document {$gt int 30}} \ +# -opts {projection document {name int 1 age int 1}}] +# +# Skip: +# old [::mongo::collection::query $mongoColl \ +# [list \$query document {projects string nsf} \$orderby document {name int -1}] \ +# -skip 1 ] +# new [::mongo::collection::query $mongoColl \ +# {projects string nsf} \ +# -opts { +# sort document {name int 1} +# skip int64 1 +# }] +# Limit: +# old [::mongo::collection::query $mongoColl \ +# [list \$query document {projects string nsf} \$orderby document {name int -1}] \ +# -limit 1 ] +# new [::mongo::collection::query $mongoColl \ +# {projects string nsf} \ +# -opts { +# sort document {name int 1} +# limit int64 1 +# }] + + package require nsf puts stderr "PWD [pwd]" @@ -86,12 +133,36 @@ puts stderr "\nFull content" ? {llength [::mongo::collection::query $mongoColl {}]} 6 +puts stderr RESULT=[::mongo::collection::query $mongoColl {}] + + puts stderr "\nProject members" ? { llength [::mongo::collection::query $mongoColl \ - [list \$query document {projects string nsf} \$orderby document {name int 1}]] + {projects string nsf} \ + -opts {sort document {name int -1}}] } 2 +set all [::mongo::collection::query $mongoColl \ + {projects string nsf} \ + -opts { + sort document {name int 1} + }] +set first [::mongo::collection::query $mongoColl \ + {projects string nsf} \ + -opts { + sort document {name int 1} + limit int64 1 + }] +set second [::mongo::collection::query $mongoColl \ + {projects string nsf} \ + -opts { + sort document {name int 1} + skip int64 1 + }] +? {llength $all} 2 +? {list [lindex $all 0]} $first +? {list [lindex $all 1]} $second package req nx::mongo nx::mongo::Class create C @@ -103,24 +174,23 @@ puts stderr "\nProject members of nsf sorted by name" ? { - set r [lindex [::mongo::collection::query $mongoColl \ - [list \$query document {projects string nsf} \$orderby document {name int 1}]] 0] + set r [lindex [::mongo::collection::query $mongoColl {projects string nsf} \ + -opts {sort document {name int 1}}] 0] string match *Gustaf* $r } 1 puts stderr "\nAge > 30 (all atts)" ? { - set r [::mongo::collection::query $mongoColl \ - [list \$query document {age document {$gt int 30}}]] + set r [::mongo::collection::query $mongoColl {age document {$gt int 30}}] set _ [llength $r]-[llength [lindex $r 0]] } 2-12 -puts stderr "\nAge > 30 (only atts name and age, aside of _id)" +puts stderr "\nAge > 30 (projection on name and age, aside of _id)" ? { set r [::mongo::collection::query $mongoColl \ - [list \$query document {age document {$gt int 30}}] \ - -atts {name int 1 age int 1}] + {age document {$gt int 30}} \ + -opts {projection document {name int 1 age int 1}}] set _ [llength $r]-[llength [lindex $r 0]] } 2-9 @@ -130,7 +200,7 @@ puts stderr "\nAge > 30 (all atts, via cursor interface)" ? { set cursor [::mongo::cursor::find $mongoColl \ - [list \$query document {age document {$gt int 30}}]] + {age document {$gt int 30}}] puts "Cursor: $cursor" set r0 [::mongo::cursor::next $cursor] set r1 [::mongo::cursor::next $cursor] @@ -142,7 +212,8 @@ puts stderr "\nAge > 30 (all atts, via cursor interface, tailable)" ? { set cursor [::mongo::cursor::find $mongoColl \ - [list \$query document {age document {$gt int 30}}] -tailable] + {age document {$gt int 30}} \ + -opts {tailable boolean true}] if {$cursor ne ""} { set r "" while {1} { @@ -171,15 +242,15 @@ puts stderr "\nArray 'a' contains 'x'" ? {llength [::mongo::collection::query $mongoColl \ - [list \$query document {a string "x"}]]} 1 + {a string "x"}]} 1 puts stderr "\nEmbedded document has some value (info.y > 100)" ? {llength [::mongo::collection::query $mongoColl \ - [list \$query document {info.y document {$gt int 100}}]]} 1 + {info.y document {$gt int 100}}]} 1 puts stderr "\nProjects in {nsf gtat}" ? { llength [::mongo::collection::query $mongoColl \ - [list \$query document {projects document {$in array {0 string nsf 1 string gtat}}}]]} 3 + {projects document {$in array {0 string nsf 1 string gtat}}}]} 3 puts stderr "\nStatistics of $mongoColl" set stats [::mongo::collection::stats $mongoColl] Index: library/mongodb/tests/nx-mongo.test =================================================================== diff -u -N -r64cdee65763cc97c7ae64f6b522c1dee4707ed6e -rab21c8502870e715c567c657146283699e31b01b --- library/mongodb/tests/nx-mongo.test (.../nx-mongo.test) (revision 64cdee65763cc97c7ae64f6b522c1dee4707ed6e) +++ library/mongodb/tests/nx-mongo.test (.../nx-mongo.test) (revision ab21c8502870e715c567c657146283699e31b01b) @@ -96,7 +96,7 @@ ? {lsort [lmap p $persons {$p cget -name}]} "Gustaf Stefan" puts "\nProject members of nsf or gtat:" -? {llength [set persons [Person find all -cond {projects in {nsf gtat}}]]} 3 +? {llength [set persons [Person find all -cond {projects in {nsf gtat}} -orderby name]]} 3 ? {lsort [lmap p $persons {$p cget -name}]} "Franz Gustaf Stefan" puts "\nProject members working on both nsf and nxmongo:"