diff --git a/generic/bson.c b/generic/bson.c index 48f38e0..e2e7e18 100644 --- a/generic/bson.c +++ b/generic/bson.c @@ -32,11 +32,11 @@ mongotcl_bsontolist_raw (Tcl_Interp *interp, Tcl_Obj *listObj, const char *data key = bson_iterator_key (&i); - switch (t) { + switch (t) { case BSON_DOUBLE: { - append_list_type_object (interp, listObj, "double", key, Tcl_NewDoubleObj (bson_iterator_double (&i))); - break; - } + append_list_type_object (interp, listObj, "double", key, Tcl_NewDoubleObj (bson_iterator_double (&i))); + break; + } case BSON_STRING: { append_list_type_object (interp, listObj, "string", key, Tcl_NewStringObj (bson_iterator_string (&i), -1)); @@ -152,6 +152,174 @@ mongotcl_bsontolist(Tcl_Interp *interp, const bson *b) { return mongotcl_bsontolist_raw (interp, listObj, b->data , 0); } +int +mongotcl_bsontoarray_raw (Tcl_Interp *interp, char *arrayName, char *typeArrayName, const char *data , int depth) { + bson_iterator i; + const char *key; + bson_timestamp_t ts; + char oidhex[25]; + Tcl_Obj *obj; + char *type; + + if (data == NULL) { + return TCL_OK; + } + + bson_iterator_from_buffer(&i, data); + + while (bson_iterator_next (&i)) { + bson_type t = bson_iterator_type (&i); + if (t == 0) { + break; + } + + key = bson_iterator_key (&i); + + switch (t) { + case BSON_DOUBLE: { + obj = Tcl_NewDoubleObj (bson_iterator_double (&i)); + type = "double"; + break; + } + + case BSON_SYMBOL: { + obj = Tcl_NewStringObj (bson_iterator_string (&i), -1); + type = "symbol"; + break; + } + + case BSON_STRING: { + obj = Tcl_NewStringObj (bson_iterator_string (&i), -1); + type = "string"; + break; + } + + case BSON_OID: { + bson_oid_to_string( bson_iterator_oid( &i ), oidhex ); + obj = Tcl_NewStringObj (oidhex, -1); + type = "oid"; + break; + } + + case BSON_BOOL: { + obj = Tcl_NewBooleanObj (bson_iterator_bool (&i)); + type = "bool"; + break; + } + + case BSON_DATE: { + obj = Tcl_NewLongObj ((long) bson_iterator_date(&i)); + type = "date"; + break; + } + + case BSON_BINDATA: { + unsigned char *bindata = (unsigned char *)bson_iterator_bin_data (&i); + int binlen = bson_iterator_bin_len (&i); + + obj = Tcl_NewByteArrayObj (bindata, binlen); + type = "bin"; + break; + } + + case BSON_UNDEFINED: { + obj = Tcl_NewObj (); + type = "undefined"; + break; + } + + case BSON_NULL: { + obj = Tcl_NewObj (); + type = "null"; + break; + } + + case BSON_REGEX: { + obj = Tcl_NewStringObj (bson_iterator_regex (&i), -1); + type = "regex"; + break; + } + + case BSON_CODE: { + obj = Tcl_NewStringObj (bson_iterator_code (&i), -1); + type = "code"; + break; + } + + case BSON_CODEWSCOPE: { + // bson_printf( "BSON_CODE_W_SCOPE: %s", bson_iterator_code( &i ) ); + /* bson_init( &scope ); */ /* review - stepped on by bson_iterator_code_scope? */ + // bson_iterator_code_scope( &i, &scope ); + // bson_printf( "\n\t SCOPE: " ); + // bson_print( &scope ); + /* bson_destroy( &scope ); */ /* review - causes free error */ + break; + } + + case BSON_INT: { + obj = Tcl_NewIntObj (bson_iterator_int (&i)); + type = "int"; + break; + } + + case BSON_LONG: { + obj = Tcl_NewLongObj ((uint64_t)bson_iterator_long (&i)); + type = "long"; + break; + } + + case BSON_TIMESTAMP: { + char string[64]; + + ts = bson_iterator_timestamp (&i); + snprintf(string, sizeof(string), "%d:%d", ts.i, ts.t); + obj = Tcl_NewStringObj (bson_iterator_string (&i), -1); + type = "timestamp"; + break; + } + + case BSON_ARRAY: { + obj = Tcl_NewObj(); + obj = mongotcl_bsontolist_raw (interp, obj, bson_iterator_value (&i), depth + 1); + type = "array"; + + break; + } + + case BSON_OBJECT: { + Tcl_Obj *subList = Tcl_NewObj (); + + obj = mongotcl_bsontolist_raw (interp, subList, bson_iterator_value (&i), depth + 1); + type = "object"; + break; + } + + default: { + obj = Tcl_NewIntObj (t); + type = "unknown"; + break; + } + } + + if (Tcl_SetVar2Ex (interp, arrayName, key, obj, TCL_LEAVE_ERR_MSG) == NULL) { + return TCL_ERROR; + } + + if (typeArrayName != NULL) { + if (Tcl_SetVar2Ex (interp, typeArrayName, key, Tcl_NewStringObj (type, -1), TCL_LEAVE_ERR_MSG) == NULL) { + return TCL_ERROR; + } + } + } + return TCL_OK; +} + +int +mongotcl_bsontoarray(Tcl_Interp *interp, char *arrayName, char *typeArrayName, const bson *b) { + return mongotcl_bsontoarray_raw (interp, arrayName, typeArrayName, b->data , 0); +} + + /* *-------------------------------------------------------------- @@ -327,6 +495,7 @@ mongotcl_bsonObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Ob "finish_object", "new_oid", "to_list", + "to_array", "finish", "print", NULL @@ -350,6 +519,7 @@ mongotcl_bsonObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Ob OPT_APPEND_FINISH_OBJECT, OPT_APPEND_NEW_OID, OPT_TO_LIST, + OPT_TO_ARRAY, OPT_FINISH, OPT_PRINT }; @@ -687,6 +857,27 @@ mongotcl_bsonObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_Ob break; } + case OPT_TO_ARRAY: { + char *arrayName; + char *typeArrayName; + + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs (interp, 1, objv, "to_array arrayName ?typeArrayName?"); + return TCL_ERROR; + } + + arrayName = Tcl_GetString (objv[2]); + + if (objc == 3) { + typeArrayName = NULL; + } else { + typeArrayName = Tcl_GetString (objv[3]); + } + + return mongotcl_bsontoarray(interp, arrayName, typeArrayName, bd->bson); + break; + } + case OPT_FINISH: { if (bson_finish (bd->bson) != BSON_OK) { return mongotcl_setBsonError (interp, bd->bson); diff --git a/generic/cursor.c b/generic/cursor.c index eecb0f9..15bab3c 100644 --- a/generic/cursor.c +++ b/generic/cursor.c @@ -210,6 +210,7 @@ mongotcl_cursorObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_ static CONST char *options[] = { "next", "to_list", + "to_array", "init", "set_query", "set_fields", @@ -223,6 +224,7 @@ mongotcl_cursorObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_ enum options { OPT_CURSOR_NEXT, OPT_CURSOR_TO_LIST, + OPT_CURSOR_TO_ARRAY, OPT_CURSOR_INIT, OPT_CURSOR_SET_QUERY, OPT_CURSOR_SET_FIELDS, @@ -408,6 +410,26 @@ mongotcl_cursorObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_ break; } + case OPT_CURSOR_TO_ARRAY: { + char *arrayName; + char *typeArrayName; + + if (objc < 3 || objc > 4) { + Tcl_WrongNumArgs (interp, 1, objv, "to_array array ?typeArray?"); + return TCL_ERROR; + } + + arrayName = Tcl_GetString (objv[2]); + + if (objc == 3) { + typeArrayName = NULL; + } else { + typeArrayName = Tcl_GetString (objv[3]); + } + + return mongotcl_bsontoarray (interp, arrayName, typeArrayName, mongo_cursor_bson (mc->cursor)); + } + case OPT_CURSOR_NEXT: { if (mongo_cursor_next (mc->cursor) == MONGO_OK) { Tcl_SetObjResult (interp, Tcl_NewBooleanObj (1)); diff --git a/generic/mongotcl.c b/generic/mongotcl.c index 9b14e8a..a83783d 100644 --- a/generic/mongotcl.c +++ b/generic/mongotcl.c @@ -177,6 +177,7 @@ mongotcl_mongoObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_O "update", "insert_batch", "cursor", + "search", "find", "count", "init", @@ -208,6 +209,7 @@ mongotcl_mongoObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_O OPT_UPDATE, OPT_INSERT_BATCH, OPT_CURSOR, + OPT_SEARCH, OPT_MONGO_FIND, OPT_COUNT, OPT_INIT, @@ -497,6 +499,24 @@ mongotcl_mongoObjectObjCmd(ClientData cData, Tcl_Interp *interp, int objc, Tcl_O break; } + case OPT_SEARCH: { + int i; + int result; + Tcl_Obj **searchObjv = (Tcl_Obj **)ckalloc(sizeof (Tcl_Obj *) * objc); + + searchObjv[0] = Tcl_NewStringObj ("mongo::_search", -1); + Tcl_IncrRefCount (searchObjv[0]); + searchObjv[1] = objv[0]; + + for (i = 2; i < objc; i++) { + searchObjv[i] = objv[i]; + } + result = Tcl_EvalObjv (interp, objc, searchObjv, 0); + Tcl_DecrRefCount (searchObjv[0]); + ckfree((char *)searchObjv); + return result; + } + case OPT_MONGO_FIND: { char *ns; bson *bsonQuery; diff --git a/generic/mongotcl.h b/generic/mongotcl.h index d3996d7..02549b8 100644 --- a/generic/mongotcl.h +++ b/generic/mongotcl.h @@ -31,6 +31,8 @@ mongotcl_cmdNameObjSetBson (Tcl_Interp *interp, Tcl_Obj *commandNameObj, bson *n extern Tcl_Obj * mongotcl_bsontolist(Tcl_Interp *interp, const bson *b); +extern int +mongotcl_bsontoarray(Tcl_Interp *interp, char *arrayName, char *typeArrayName, const bson *b); extern int mongotcl_mongoObjCmd(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objvp[]);