Index: Makefile.in =================================================================== diff -u -rc08415f59c4ce753f976d0513d6208426772ef2a -r5c3834b15078b31970db26d0c65030ed1f66b18d --- Makefile.in (.../Makefile.in) (revision c08415f59c4ce753f976d0513d6208426772ef2a) +++ Makefile.in (.../Makefile.in) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -494,7 +494,14 @@ gdb: $(TCLSH_ENV) gdb $(TCLSH_PROG) $(SCRIPT) -test: binaries libraries test-core test-xotcl test-http @test_actiweb@ test-summary +test: binaries libraries test-core test-xotcl test-http @test_actiweb@ + @if test ! "x$(subdirs)" = "x" ; then dirs="$(subdirs)" ; \ + for dir in $$dirs ; do \ + if (cd $$dir; $(MAKE) $@) ; then true ; else exit 1 ; fi ; \ + done; fi + $(TCLSH) $(src_test_dir_native)/summary.tcl -title NX+XOTcl -libdir $(PLATFORM_DIR) $(TESTFLAGS) + + test-nohttp: binaries libraries test-core test-xotcl TESTLOG = ./__test.log @@ -565,6 +572,10 @@ $(TCLSH) $(xotcl_src_test_dir)/xoRDF.test -libdir $(PLATFORM_DIR) $(TESTFLAGS) @rm -rf receiver +test-mongodb: $(TCLSH_PROG) + $(MAKE) $@ + + depend: Index: TODO =================================================================== diff -u -rc08415f59c4ce753f976d0513d6208426772ef2a -r5c3834b15078b31970db26d0c65030ed1f66b18d --- TODO (.../TODO) (revision c08415f59c4ce753f976d0513d6208426772ef2a) +++ TODO (.../TODO) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -4712,6 +4712,15 @@ - tested with mongodb 2.4.5 - added example scripts rosetta-sudoku.{tcl,html} and tk-ludo.{tcl,html} + +mongodb: +- integrated configuration of mongodb into toplevel configfile + option: --with-mongodb=MONGO_INCLUDE_DIR,MONGO_LIB_DIR +- added regression test files for mongodb support + (lowlevel (tcl-only) and highlevel (nx based oo support)) +- integrated mongodb-testfiles with "make test" +- reduced verbosity of nx-mongo.tcl (added verbosty variable) + ======================================================================== TODO: Index: configure =================================================================== diff -u -rcf7d34f7694dfd51070e0c175213a99b700752af -r5c3834b15078b31970db26d0c65030ed1f66b18d --- configure (.../configure) (revision cf7d34f7694dfd51070e0c175213a99b700752af) +++ configure (.../configure) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -701,6 +701,7 @@ NSF_MINOR_VERSION NSF_MAJOR_VERSION NSF_VERSION +test_mongodb subdirs PKG_CFLAGS PKG_LIBS @@ -756,6 +757,7 @@ enable_option_checking with_aolserver3 with_dtrace +with_mongodb enable_profile enable_memcount enable_development @@ -1414,6 +1416,8 @@ build an AOLserver 3 module; point to directory containing aolsever/include (default: off) --with-dtrace build nsf with dtrace (default: without) + --with-mongodb=MONGO_INCLUDE_DIR,MONGO_LIB_DIR + build nsf with mongodb support (default: without) --with-tcl directory containing tcl configuration (tclConfig.sh) --with-tclinclude directory containing the public Tcl header files @@ -2389,6 +2393,14 @@ with_dtrace=no fi + +# Check whether --with-mongodb was given. +if test "${with_mongodb+set}" = set; then : + withval=$with_mongodb; with_mongodb=$withval +else + with_mongodb=no +fi + # Check whether --enable-profile was given. if test "${enable_profile+set}" = set; then : enableval=$enable_profile; enable_profile=$enableval @@ -2426,14 +2438,21 @@ subdirs="" +test_mongodb="" +if ! test "$with_mongodb" = no; then + test_mongodb=test-mongdb + subdirs="$subdirs library/mongodb" +fi + test_actiweb="" libdirs_actiweb="" apps_actiweb="" + #-------------------------------------------------------------------- # __CHANGE__ # Set your package name and version numbers here. The NODOT_VERSION is @@ -10148,7 +10167,7 @@ mkdir -p $subdir confdir=${srcdir}/$subdir fi - (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-xotcl=${here}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-xotcl=${here}) + (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${here}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${here}) done Index: configure.ac =================================================================== diff -u -rcf7d34f7694dfd51070e0c175213a99b700752af -r5c3834b15078b31970db26d0c65030ed1f66b18d --- configure.ac (.../configure.ac) (revision cf7d34f7694dfd51070e0c175213a99b700752af) +++ configure.ac (.../configure.ac) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -37,6 +37,10 @@ AC_ARG_WITH(dtrace, AC_HELP_STRING([--with-dtrace], [build nsf with dtrace (default: without)]), [with_dtrace=$withval], [with_dtrace=no]) +AC_ARG_WITH(mongodb, + AC_HELP_STRING([--with-mongodb=MONGO_INCLUDE_DIR[,MONGO_LIB_DIR]], + [build nsf with mongodb support (default: without)]), + [with_mongodb=$withval], [with_mongodb=no]) AC_ARG_ENABLE(profile, AC_HELP_STRING([--enable-profile], [build nsf with profile support (default: disabled)]), [enable_profile=$enableval], [enable_profile=no]) @@ -58,12 +62,19 @@ [enable_assemble=$enableval], [enable_assemble=no]) subdirs="" +test_mongodb="" +if ! test "$with_mongodb" = no; then + test_mongodb=test-mongdb + subdirs="$subdirs library/mongodb" +fi + test_actiweb="" libdirs_actiweb="" apps_actiweb="" AC_SUBST(subdirs) +AC_SUBST(test_mongodb) #-------------------------------------------------------------------- @@ -443,7 +454,7 @@ mkdir -p $subdir confdir=${srcdir}/$subdir fi - (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-xotcl=${here}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-xotcl=${here}) + (cd $subdir; echo $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${here}; eval $SHELL ${confdir}/configure ${ac_configure_args} --prefix=${prefix} --with-nsf=${here}) done Index: library/mongodb/Makefile.in =================================================================== diff -u -rc81b840c71a9f0de9d0a502e3e4ddfde57b81fdd -r5c3834b15078b31970db26d0c65030ed1f66b18d --- library/mongodb/Makefile.in (.../Makefile.in) (revision c81b840c71a9f0de9d0a502e3e4ddfde57b81fdd) +++ library/mongodb/Makefile.in (.../Makefile.in) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -219,9 +219,20 @@ # $(INSTALL_DATA) $$i $(DESTDIR)$(mandir)/mann ; \ # done +TESTLOG = ./__test.log +TESTFLAGS = -testlog $(TESTLOG) + test: binaries libraries - $(TCLSH) `@CYGPATH@ $(srcdir)/tests/all.tcl` $(TESTFLAGS) + rm -f $(TESTLOG) + $(TCLSH) $(srcdir)/tests/nsf-mongo.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/tests/nsf-gridfs.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/tests/nx-bi.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/tests/nx-mongo.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/tests/nx-reference-one.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/tests/nx-reference-many.test -libdir . $(TESTFLAGS) + $(TCLSH) $(srcdir)/../../tests/summary.tcl -title MongoDB -libdir . $(TESTFLAGS) + shell: binaries libraries @$(TCLSH) $(SCRIPT) Index: library/mongodb/configure =================================================================== diff -u -rf265d8b18ef1925998a3ab7169f8d642769e6212 -r5c3834b15078b31970db26d0c65030ed1f66b18d --- library/mongodb/configure (.../configure) (revision f265d8b18ef1925998a3ab7169f8d642769e6212) +++ library/mongodb/configure (.../configure) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -1,11 +1,9 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for nsfmongo 0.1. +# Generated by GNU Autoconf 2.69 for nsfmongo 0.1. # # -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, -# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software -# Foundation, Inc. +# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation @@ -134,6 +132,31 @@ # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH +# Use a proper internal environment variable to ensure we don't fall + # into an infinite loop, continuously re-executing ourselves. + if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then + _as_can_reexec=no; export _as_can_reexec; + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +as_fn_exit 255 + fi + # We don't want this to propagate to other subprocesses. + { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh @@ -167,7 +190,8 @@ else exitcode=1; echo positional parameters were not saved. fi -test x\$exitcode = x0 || exit 1" +test x\$exitcode = x0 || exit 1 +test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && @@ -212,21 +236,25 @@ if test "x$CONFIG_SHELL" != x; then : - # We cannot yet assume a decent shell, so we have to provide a - # neutralization value for shells without unset; and this also - # works around shells that cannot unset nonexistent variables. - # Preserve -v and -x to the replacement shell. - BASH_ENV=/dev/null - ENV=/dev/null - (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV - export CONFIG_SHELL - case $- in # (((( - *v*x* | *x*v* ) as_opts=-vx ;; - *v* ) as_opts=-v ;; - *x* ) as_opts=-x ;; - * ) as_opts= ;; - esac - exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} + export CONFIG_SHELL + # We cannot yet assume a decent shell, so we have to provide a +# neutralization value for shells without unset; and this also +# works around shells that cannot unset nonexistent variables. +# Preserve -v and -x to the replacement shell. +BASH_ENV=/dev/null +ENV=/dev/null +(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV +case $- in # (((( + *v*x* | *x*v* ) as_opts=-vx ;; + *v* ) as_opts=-v ;; + *x* ) as_opts=-x ;; + * ) as_opts= ;; +esac +exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} +# Admittedly, this is quite paranoid, since all the known shells bail +# out after a failed `exec'. +$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 +exit 255 fi if test x$as_have_required = xno; then : @@ -328,6 +356,14 @@ } # as_fn_mkdir_p + +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take @@ -449,6 +485,10 @@ chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + # If we had to re-execute with $CONFIG_SHELL, we're ensured to have + # already done that, so ensure we don't try to do so again and fall + # in an infinite loop. This has already happened in practice. + _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). @@ -483,16 +523,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -504,28 +544,8 @@ as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +as_test_x='test -x' +as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -707,7 +727,7 @@ ac_subst_files='' ac_user_opts=' enable_option_checking -with_mongo +with_mongodb with_nsf with_tcl with_tclinclude @@ -1184,8 +1204,6 @@ if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe - $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. - If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi @@ -1351,9 +1369,9 @@ Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) - --with-mongo=MONGO_INCLUDE_DIR,MONGO_LIB_DIR + --with-mongodb=MONGO_INCLUDE_DIR,MONGO_LIB_DIR absolute path to bson.h and optionally the path to the library, - --without-mongo disables build of the mongo interface + --without-mongodb disables build of the mongo interface --with-nsf=DIR_CONTAINING_NSFCONFIG_SH absolute path to nsfConfig.sh, --without-nsf disables, but this is pointless @@ -1439,9 +1457,9 @@ if $ac_init_version; then cat <<\_ACEOF nsfmongo configure 0.1 -generated by GNU Autoconf 2.68 +generated by GNU Autoconf 2.69 -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF @@ -1627,7 +1645,7 @@ test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || - $as_test_x conftest$ac_exeext + test -x conftest$ac_exeext }; then : ac_retval=0 else @@ -1804,7 +1822,7 @@ running configure, to aid debugging if configure makes a mistake. It was created by nsfmongo $as_me 0.1, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2197,7 +2215,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CYGPATH="cygpath -w" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2296,11 +2314,11 @@ # specify some extra flags #-------------------------------------------------------------------- -# Check whether --with-mongo was given. -if test "${with_mongo+set}" = set; then : - withval=$with_mongo; with_mongo=$withval +# Check whether --with-mongodb was given. +if test "${with_mongodb+set}" = set; then : + withval=$with_mongodb; with_mongodb=$withval else - with_mongo=no + with_mongodb=no fi @@ -2657,7 +2675,7 @@ # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. @@ -2745,7 +2763,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2785,7 +2803,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2838,7 +2856,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2879,7 +2897,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue @@ -2937,7 +2955,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -2981,7 +2999,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3427,8 +3445,7 @@ /* end confdefs.h. */ #include #include -#include -#include +struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); @@ -3710,7 +3727,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3750,7 +3767,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_RANLIB="ranlib" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -3811,7 +3828,7 @@ for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in @@ -3877,7 +3894,7 @@ for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" - { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in @@ -4810,9 +4827,9 @@ # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- -if test ! "${with_mongo}" = no; then - MONGO_INC_DIR="`echo $with_mongo |cut -f1 -d,`" - MONGO_LIB_DIR="`echo $with_mongo |cut -f2 -d, -s`" +if test ! "${with_mongodb}" = no; then + MONGO_INC_DIR="`echo $with_mongodb |cut -f1 -d,`" + MONGO_LIB_DIR="`echo $with_mongodb |cut -f2 -d, -s`" fi if test -z "$MONGO_INC_DIR" ; then gdbm_h_ok=1 @@ -5636,7 +5653,7 @@ IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do - if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AR="ar" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 @@ -8088,16 +8105,16 @@ # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. - # In both cases, we have to default to `cp -p'. + # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || - as_ln_s='cp -p' + as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi else - as_ln_s='cp -p' + as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null @@ -8157,29 +8174,17 @@ as_mkdir_p=false fi -if test -x / >/dev/null 2>&1; then - as_test_x='test -x' -else - if ls -dL / >/dev/null 2>&1; then - as_ls_L_option=L - else - as_ls_L_option= - fi - as_test_x=' - eval sh -c '\'' - if test -d "$1"; then - test -d "$1/."; - else - case $1 in #( - -*)set "./$1";; - esac; - case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( - ???[sx]*):;;*)false;;esac;fi - '\'' sh - ' -fi -as_executable_p=$as_test_x +# as_fn_executable_p FILE +# ----------------------- +# Test if FILE is an executable regular file. +as_fn_executable_p () +{ + test -f "$1" && test -x "$1" +} # as_fn_executable_p +as_test_x='test -x' +as_executable_p=as_fn_executable_p + # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" @@ -8200,7 +8205,7 @@ # values after options handling. ac_log=" This file was extended by nsfmongo $as_me 0.1, which was -generated by GNU Autoconf 2.68. Invocation command line was +generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS @@ -8253,10 +8258,10 @@ ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ nsfmongo config.status 0.1 -configured by $0, generated by GNU Autoconf 2.68, +configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" -Copyright (C) 2010 Free Software Foundation, Inc. +Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." @@ -8334,7 +8339,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then - set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' Index: library/mongodb/configure.ac =================================================================== diff -u -r42ba8471f7620b850b6296f753cbc3079fe5c6cd -r5c3834b15078b31970db26d0c65030ed1f66b18d --- library/mongodb/configure.ac (.../configure.ac) (revision 42ba8471f7620b850b6296f753cbc3079fe5c6cd) +++ library/mongodb/configure.ac (.../configure.ac) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -35,11 +35,11 @@ #-------------------------------------------------------------------- # specify some extra flags #-------------------------------------------------------------------- -AC_ARG_WITH(mongo, - [ --with-mongo=MONGO_INCLUDE_DIR[,MONGO_LIB_DIR] +AC_ARG_WITH(mongodb, + [ --with-mongodb=MONGO_INCLUDE_DIR[,MONGO_LIB_DIR] absolute path to bson.h and optionally the path to the library, - --without-mongo disables build of the mongo interface], - [with_mongo=$withval], [with_mongo=no]) + --without-mongodb disables build of the mongo interface], + [with_mongodb=$withval], [with_mongodb=no]) AC_ARG_WITH(nsf, [ --with-nsf=DIR_CONTAINING_NSFCONFIG_SH @@ -86,9 +86,9 @@ # This defines PKG(_STUB)_SOURCES, PKG(_STUB)_OBJECTS, PKG_HEADERS # and PKG_TCL_SOURCES. #----------------------------------------------------------------------- -if test ! "${with_mongo}" = no; then - MONGO_INC_DIR="`echo $with_mongo |cut -f1 -d,`" - MONGO_LIB_DIR="`echo $with_mongo |cut -f2 -d, -s`" +if test ! "${with_mongodb}" = no; then + MONGO_INC_DIR="`echo $with_mongodb |cut -f1 -d,`" + MONGO_LIB_DIR="`echo $with_mongodb |cut -f2 -d, -s`" fi if test -z "$MONGO_INC_DIR" ; then gdbm_h_ok=1 Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nsf-gridfs.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nsf-mongo.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nx-bi.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nx-mongo.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nx-reference-many.tcl'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 5c3834b15078b31970db26d0c65030ed1f66b18d refers to a dead (removed) revision in file `library/mongodb/example-nx-reference-one.tcl'. Fisheye: No comparison available. Pass `N' to diff? Index: library/mongodb/nsfmongo.c =================================================================== diff -u -rbfc9f64e6e94f265a27a32d5f7faf0763ae1c9e3 -r5c3834b15078b31970db26d0c65030ed1f66b18d --- library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision bfc9f64e6e94f265a27a32d5f7faf0763ae1c9e3) +++ library/mongodb/nsfmongo.c (.../nsfmongo.c) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -670,7 +670,7 @@ /* TODO: examples in mongo-client do not touch out; do we have to do something about it? */ - Tcl_SetObjResult(interp, Tcl_NewBooleanObj(success)); + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(success == MONGO_OK)); return TCL_OK; } @@ -821,7 +821,7 @@ static int NsfMongoUpdate(Tcl_Interp *interp, mongo *connPtr, CONST char *namespace, Tcl_Obj *conditionObj, Tcl_Obj *valuesObj, int withUpsert, int withAll) { - int objc, result, options = 0; + int objc, result, mongorc, options = 0; Tcl_Obj **objv; bson cond[1], values[1]; @@ -844,8 +844,10 @@ if (withAll) {options |= 2;} /* for the time being, no write_concern (last arg of mongo_update()) */ - mongo_update(connPtr, namespace, cond, values, options, NULL); - + mongorc = mongo_update(connPtr, namespace, cond, values, options, NULL); + + Tcl_SetObjResult(interp, Tcl_NewBooleanObj(mongorc == MONGO_OK)); + return TCL_OK; } Index: library/mongodb/nx-mongo.tcl =================================================================== diff -u -r42ba8471f7620b850b6296f753cbc3079fe5c6cd -r5c3834b15078b31970db26d0c65030ed1f66b18d --- library/mongodb/nx-mongo.tcl (.../nx-mongo.tcl) (revision 42ba8471f7620b850b6296f753cbc3079fe5c6cd) +++ library/mongodb/nx-mongo.tcl (.../nx-mongo.tcl) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -5,7 +5,7 @@ # package require nx package require nsf::mongo -package provide nx::mongo 0.3 +package provide nx::mongo 0.4 # todo: how to handle multiple connections; currently we have a single, global connection # todo: all references are currently auto-fetched. make this optional @@ -20,8 +20,11 @@ namespace eval ::nx::mongo { + set ::nx::mongo::log 1 + ::nx::Object create ::nx::mongo::db { :object property db + :object property mongoConn :public object method connect {{-db test} args} { set :db $db set :mongoConn [::mongo::connect {*}$args] @@ -35,6 +38,7 @@ :public object method "drop collection" {name} {::mongo::run -nocomplain ${:mongoConn} ${:db} [list drop string $name]} :public object method "drop database" {} {::mongo::run -nocomplain ${:mongoConn} ${:db} [list dropDatabase integer 1]} :public object method "reset error" {} {::mongo::run -nocomplain ${:mongoConn} ${:db} [list reseterror integer 1]} + :public object method is_oid {string} {expr {[string length $string] == 24}} } ####################################################################### @@ -43,6 +47,15 @@ ::nx::MetaSlot create ::nx::mongo::Attribute -superclass ::nx::VariableSlot { :property mongotype + # + # manage logging of mongo concerns + # + :public method log {msg} { + if {$::nx::mongo::log} { + nsf::log notice "mongo-attribute: $msg" + } + } + :protected method init {} { # # If the mongotype was not provided, set it to a value derived @@ -107,10 +120,14 @@ error "value to be dereferenced does not contain dbref id: $value" } if {[info exists (db)]} { - if {$(db) ne [$class mongo_db]} {error "$(db) is different to [$class mongo_db]"} + if {$(db) ne [$class cget -mongo_db]} { + error "$(db) is different to [$class cget -mongo_db]" + } } if {[info exists (ref)]} { - if {$(ref) ne [$class mongo_collection]} {error "$(ref) is different to [$class mongo_collection]"} + if {$(ref) ne [$class cget -mongo_collection]} { + error "$(ref) is different to [$class cget -mongo_collection]" + } } return [$class find first -cond [list _id = $(id)]] } @@ -120,15 +137,15 @@ return [list object [$value bson encode]] } elseif {${:mongotype} eq "referenced_object"} { if {![::nsf::var::exists $value _id]} { - puts stderr "autosave $value to obtain an object_id" + :log "autosave $value to obtain an object_id" $value save } set _id [$value cget -_id] set cls [$value info class] return [list object [list \ - {$ref} string [$cls mongo_collection] \ + {$ref} string [$cls cget -mongo_collection] \ {$id} oid $_id \ - {$db} string [$cls mongo_db]]] + {$db} string [$cls cget -mongo_db]]] } else { return [list ${:mongotype} $value] } @@ -219,7 +236,6 @@ # (property name or operator name) internal representations # (eg. mongo type, or mongo operator). # - :method "get slot" {att} { set classes [concat [self] [:info mixin classes] [:info heritage]] foreach cls $classes { @@ -416,7 +432,7 @@ [:bson query -cond $cond -orderby $orderby] \ -atts [:bson atts $atts] \ {*}$opts] - puts "[join $fetched \n]" + #puts "[join $fetched \n]" foreach tuple $fetched { lappend result [:bson create $tuple] } @@ -484,6 +500,15 @@ ::nx::Class create ::nx::mongo::Object { # + # manage logging of mongo concerns + # + :public method log {msg} { + if {$::nx::mongo::log} { + nsf::log notice "mongo: $msg" + } + } + + # # _id is the special property maintained by mongoDB # :property -class ::nx::mongo::Attribute _id { @@ -512,7 +537,7 @@ if {[array exists :__contains]} { # destroy embedded object foreach o [array names :__contains] { - puts "[self] contains $o -> destroy" + :log "[self] contains $o -> destroy" $o destroy } } @@ -527,7 +552,6 @@ # delete the current object from the db # :public method delete {} { - puts stderr "[self] delete" if {[info exists :__embedded_in]} { # When an embedded object is deleted, it is removed for the # reference list. The containing object is not automatically @@ -539,19 +563,19 @@ if {$slot eq ""} {error "could not obtain slot for <$att $op $value>"} $slot remove $parent [self] #puts stderr [:serialize] - puts stderr "[self] must save parent $parent in db" + :log "[self] must save parent $parent in db" :destroy } elseif {[info exists :__referenced_in]} { # When a referenced is deleted, we do for now essentially the # same as for embedded objects. However, the same object might # be referenced by several objects. - puts "[self] is referenced in ${:__referenced_in}" + #puts "[self] is referenced in ${:__referenced_in}" foreach reference ${:__referenced_in} { lassign $reference parent att set slot [[$parent info class] get slot $att] if {$slot eq ""} {error "could not obtain slot for <$att $op $value>"} $slot remove $parent [self] - puts stderr "[self] must save parent $parent in db" + :log "[self] must save parent $parent in db" } :destroy } else { @@ -578,10 +602,11 @@ } else { set bson [:bson encode] if {[info exists :_id]} { - puts stderr "we have to update [[:info class] bson pp -indent 4 $bson]" + :log "we have to update [[:info class] bson pp -indent 4 $bson]" ::nx::mongo::db update $mongo_ns [list _id oid ${:_id}] $bson + set :_id } else { - puts stderr "we have to insert [[:info class] bson pp -indent 4 $bson]" + :log "we have to insert [[:info class] bson pp -indent 4 $bson]" set r [::nx::mongo::db insert $mongo_ns $bson] set :_id [lindex $r 2] } Index: library/mongodb/tests/nsf-gridfs.test =================================================================== diff -u --- library/mongodb/tests/nsf-gridfs.test (revision 0) +++ library/mongodb/tests/nsf-gridfs.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,119 @@ +# -*- tcl -*- +# +# This test suite tests some basic interactions from the nsf mongo +# interface with gridFS. It connects to mongoDB, opens a GridFS named +# "myfs" and inserts a file into the file systems. Run the script +# with the current directory of nsfmongo, such it can find the README +# file. +# +# After running the script, one can use the following command to +# inspect the content in the GridFS via the mongo shell +# +# $ mongo +# > use myfs +# > show collections +# > db.fs.files.find() +# +# or via the mongofiles interface: +# +# $ mongofiles -d myfs list +# + +package require nx::test +package require nsf::mongo + +# +# First, as usual, open the connection to the mongo db +# +? {set mongoConn [::mongo::connect]} mongo:0 + +# +# Open a GridFS in the mongo datbase "myfs" and use the usual prefix +# "fs", such GridFS names the collections "fs.chunks" and "fs.files". +# +? {set gridFS [::mongo::gridfs::open $mongoConn myfs fs]} gridfs:0 + + +set fn README +# gridfs::remove_file removes all files with the specified name +# multiple store operations create "revisions" with different uploadDates +::mongo::gridfs::remove_file $gridFS $fn + +# make sure, nothing else is stored there. +::mongo::remove $mongoConn myfs.fs.files {} + +# +# The current version of gridfs_store_file() is quite unfriendly, +# since it assumes that the file exists, and aborts otherwise. So, we +# perform the existence test here. +# +# Store a known file: +# +? {::mongo::gridfs::store_file $gridFS $fn $fn text/plain} 1 + +# +# Open a grid file, get some of its properties, and read it in chunks +# of 500 bytes, and close it finally. +# +? {set f [mongo::gridfile::open $gridFS README]} gridfile:0 +? {mongo::gridfile::get_metadata $f} "" +? {mongo::gridfile::get_contentlength $f} 5611 +? {mongo::gridfile::get_contenttype $f} text/plain +? { + set chunks 0 + while {1} { + set chunk [mongo::gridfile::read $f 500] + if {[string length $chunk] < 500} { + break + } + incr chunks + } + set chunks +} 11 +? {mongo::gridfile::close $f} "" + +# +# Access the files stored in the gridfs via plain query interface. +# (should be just one) +puts "\nAll Files:" +? {llength [::mongo::query $mongoConn myfs.fs.files {}]} 1 + +# +# Get the file named README from the gridfs via plain query interface +# +? {set files [::mongo::query $mongoConn myfs.fs.files \ + [list \$query object {filename string README}] \ + -limit 1] + llength [lindex $files 0] +} 24 + +# +# Extract the oid from the bson attributes +# +? { + foreach {name type value} [lindex $files 0] { + if {$name eq "_id"} {set oid $value; break} + } + expr {$oid ne ""} +} 1 + +# +# Add a dc:creator to the bson attributes +# and update the entry in the gridfs +# +? {::mongo::update $mongoConn myfs.fs.files [list _id oid $oid] \ + [concat [lindex $files 0] [list metadata object {dc:creator string "Gustaf Neumann"}]] +} 1 +# +# Now we can use the gridfs interface to obtain the additional +# metadata as well +# +set f [mongo::gridfile::open $gridFS README] +? {mongo::gridfile::get_metadata $f} "dc:creator string {Gustaf Neumann}" +mongo::gridfile::close $f + +# +# close everything +# +::mongo::gridfs::close $gridFS +::mongo::close $mongoConn Index: library/mongodb/tests/nsf-mongo.test =================================================================== diff -u --- library/mongodb/tests/nsf-mongo.test (revision 0) +++ library/mongodb/tests/nsf-mongo.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,134 @@ +# -*- tcl -*- +# +# This is a sample test set using the low-level (pure tcl) interface +# for inserting and querying tuples into MongoDB. +# +package require nsf +package require nx::test +package require nsf::mongo + +#nsf::configure debug 2 +# +# One might query the resulting tuples from the mongo shell via: +# +# mongo +# > use tutorial +# > db.persons.find(); +# + +#set mongoConn [::mongo::connect -server 127.0.0.1:27017] +set mongoConn [::mongo::connect] +puts "Connection: $mongoConn" + +if {1} { + #::mongo::remove $mongoConn tutorial.persons {} + # Drop old potenially old collection and + # recreate it as a capped collection + ::mongo::run -nocomplain $mongoConn tutorial {drop string persons} + puts "\nCreate a capped collection:" + ? {::mongo::run $mongoConn tutorial { + create string persons + capped bool 1 + size int 100000 + }} 1 + + puts "\nInserting a few tuples" + ? { + set r [::mongo::insert $mongoConn tutorial.persons [list name string Joe projects string abc age int 23 \ + classes array {0 object {$ref string courses $id oid 1}}]] + string match "_id oid *" $r + } 1 + + ::mongo::insert $mongoConn tutorial.persons [list name string Gustaf projects string nsf age int 53] + ::mongo::insert $mongoConn tutorial.persons [list name string Stefan projects string nsf] + ::mongo::insert $mongoConn tutorial.persons [list name string Franz info object {x int 203 y int 102} age int 29 projects string gtat] + ::mongo::insert $mongoConn tutorial.persons [list name string Victor a array {0 string "x" 1 string "y"} age int 31] + ::mongo::insert $mongoConn tutorial.persons [list name string Selim ts timestamp {1302945037 1} d date 1302947619279] + + puts stderr "\nCreate an index on name (ascending)" + ? {::mongo::index $mongoConn tutorial.persons [list name int 1]} 1 +} + +puts stderr "\nFull content" +? {llength [::mongo::query $mongoConn tutorial.persons {}]} 6 + +puts stderr "\nProject members" +? { + llength [::mongo::query $mongoConn tutorial.persons \ + [list \$query object {projects string nsf} \$orderby object {name int 1}]] +} 2 + +puts stderr "\nProject members of nsf sorted by name" +? { + set r [lindex [::mongo::query $mongoConn tutorial.persons \ + [list \$query object {projects string nsf} \$orderby object {name int 1}]] 0] + string match *Gustaf* $r +} 1 + +puts stderr "\nAge > 30 (all atts)" +? { + set r [::mongo::query $mongoConn tutorial.persons [list \$query object {age object {$gt int 30}}]] + set _ [llength $r]-[llength [lindex $r 0]] +} 2-12 + + +puts stderr "\nAge > 30 (only atts name and age, aside of _id)" +? { + set r [::mongo::query $mongoConn tutorial.persons [list \$query object {age object {$gt int 30}}] \ + -atts {name int 1 age int 1}] + set _ [llength $r]-[llength [lindex $r 0]] +} 2-9 + +puts stderr "\nCount Age > 30" +? {::mongo::count $mongoConn tutorial.persons {age object {$gt int 30}}} 2 + +puts stderr "\nAge > 30 (all atts, via cursor interface)" +? { + set cursor [::mongo::cursor::find $mongoConn tutorial.persons [list \$query object {age object {$gt int 30}}]] + puts "Cursor: $cursor" + set r0 [::mongo::cursor::next $cursor] + set r1 [::mongo::cursor::next $cursor] + set r2 [::mongo::cursor::next $cursor] + ::mongo::cursor::close $cursor + set _ [llength $r0]-[llength $r1]-[llength $r2] +} 12-12-0 + +puts stderr "\nAge > 30 (all atts, via cursor interface, tailable)" +? { + set cursor [::mongo::cursor::find $mongoConn tutorial.persons [list \$query object {age object {$gt int 30}}] -tailable] + if {$cursor ne ""} { + set r "" + while {1} { + lappend r [::mongo::cursor::next $cursor] + if {[lindex $r end] eq ""} break + } + ::mongo::cursor::close $cursor + join [lmap x $r {llength $x}] - + } +} 12-12-0 + +puts stderr "\nEmpty result (via cursor interface)" +? { + set cursor [::mongo::cursor::find $mongoConn tutorial.persons [list \$query object {age object {$gt int 300}}]] + if {$cursor ne ""} { + set r {} + while {1} { + lappend r [::mongo::cursor::next $cursor] + if {[lindex $r end] eq ""} break + } + ::mongo::cursor::close $cursor + join [lmap x $r {llength $x}] - + } +} 0 + +puts stderr "\nArray 'a' contains 'x'" +? {llength [::mongo::query $mongoConn tutorial.persons [list \$query object {a string "x"}]]} 1 + +puts stderr "\nEmbedded object has some value (info.y > 100)" +? {llength [::mongo::query $mongoConn tutorial.persons [list \$query object {info.y object {$gt int 100}}]]} 1 + +puts stderr "\nProjects in {nsf gtat}" +? { llength [::mongo::query $mongoConn tutorial.persons \ + [list \$query object {projects object {$in array {0 string nsf 1 string gtat}}}]]} 3 + +::mongo::close $mongoConn Index: library/mongodb/tests/nx-bi.test =================================================================== diff -u --- library/mongodb/tests/nx-bi.test (revision 0) +++ library/mongodb/tests/nx-bi.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,182 @@ +# -*- tcl -*- +# +# An example for the usage of the nx mongo object mapping based on the +# the real world +# +# "Business Insider" Data Model +# +# (see e.g. +# http://www.slideshare.net/mongodb/nosql-the-shift-to-a-nonrelational-world). +# +# { title: 'Too Big to Fail', +# author: 'John S.', +# ts: Date('05-Nov-09 10:33'), +# [ comments: [ {author: 'Ian White', +# comment: 'Great Article!' }, +# {author: 'Joe Smith', +# comment: 'But how fast is it?', +# replies: [ {author: Jane Smith', +# comment: 'scalable?' }] +# } +# ], +# tags: ['finance', 'economy'] +# } +# +# +# +# Gustaf Neumann fecit, May 2011 +# +package require nx::mongo +package require nx::serializer +package require nx::test + +#nsf::configure debug 2 + +# Establish connection to the database +::nx::mongo::db connect -db "tutorial" + +# Make sure, we start always from scratch, so remove everything from +# the collection. +nx::mongo::db drop collection postings + +###################################################################### +# Create the application classes based on the "Business Insider" data +# model. Note that instances of the class "Comment" can be embedded in +# a posting (property "comments") as well as in an comment itself +# (property "replies"). All comments are in this example multivalued +# and incremental (i.e. one can use slot methods "... add ..." and +# "... delete ..." to add values to the attributes). +# +nx::mongo::Class create Comment { + :property author:required + :property comment:required + :property -incremental replies:embedded,type=::Comment,0..n +} + +nx::mongo::Class create Posting { + :index tags + :property title:required + :property author:required + :property ts:required + :property -incremental comments:embedded,type=::Comment,0..n + :property -incremental tags:0..n +} + +###################################################################### +# Build a composite Posting instance based on the example above. +# +set p [Posting new -title "Too Big to Fail" -author "John S." \ + -ts "05-Nov-09 10:33" -tags {finance economy} \ + -comments [list \ + [Comment new -author "Ian White" -comment "Great Article!"] \ + [Comment new -author "Joe Smith" -comment "But how fast is it?" \ + -replies [list [Comment new -author "Jane Smith" -comment "scalable?"]]] \ + ]] +# +# When we save the item, the embedded objects (the comments and +# replies) are saved together with the posting in a compound document. +# +$p save + +# After saving the item, the main object contains an _id, such that a +# subsequent save operations do not create an additional entries in +# the database. For our little experiment here, we like to save +# multiple copies to see the results of our changes. Therefore we +# remove the _id manually: +$p eval {unset :_id} + +# We have two comments for the posting $p +? [list llength [$p comments]] 2 + +# Now we want to remove e.g. the second comment (with the embedded +# replies). First get this comment object $c ... +set c [lindex [$p comments] 1] + +# ... and delete it +$c delete + +# The delete operation destroy the embedded object and removes the +# reference to it in the comments property. +? [list llength [$p comments]] 1 + +# The delete operation does not automatically persist the change, +# since there might be multiple changes in a complex +# document. Therefore we have to perform an save operation of the +# containing document. +$p save + +# Now, we have two postings in the database, the first with the two +# comments, the second one with just a single comment. +? {Posting count} 2 + +# Again, we want to continue with our test and remove the fresh _id as +# well. +$p eval {unset :_id} + +# We add an additional comment at the end of the list of the comments +# with the incremental operations (the slot is incremental) ... +$p comments add [Comment new -author "Gustaf N" -comment "This sounds pretty cool"] end + +# ... and we add another tag ... +$p tags add nx + +# ... and save everything +$p save + +# We have now three entries in the database collection. +? {Posting count} 3 + +# Now fetch the first entry with the tag "nx" +set q [Posting find first -cond {tags = nx}] + +# The fetched entry should have the two comments: +? [list llength [$q comments]] 2 + +# We add jet another tag and save it +$q tags add nsf +$q save + +# We still have three entries in the database +? {Posting count} 3 + +Posting show + +puts stderr ====EXIT +###################################################################### +# Output +###################################################################### +# { +# _id: 4daaeb04727b2b1000000000, +# title: {Too Big to Fail}, +# comments: [ { +# author: {Ian White}, +# comment: {Great Article!} }, { +# replies: [ { +# author: {Jane Smith}, +# comment: scalable? } ], +# author: {Joe Smith}, +# comment: {But how fast is it?} } ], +# author: {John S.}, +# ts: {05-Nov-09 10:33}, +# tags: [ finance, economy ] +# }, { +# _id: 4daaeb04727b2b1000000001, +# title: {Too Big to Fail}, +# comments: [ { +# author: {Ian White}, +# comment: {Great Article!} } ], +# author: {John S.}, +# ts: {05-Nov-09 10:33}, +# tags: [ finance, economy ] +# }, { +# _id: 4daaeb04727b2b1000000002, +# title: {Too Big to Fail}, +# comments: [ { +# author: {Ian White}, +# comment: {Great Article!} }, { +# author: {Gustaf N}, +# comment: {This sounds pretty cool} } ], +# author: {John S.}, +# ts: {05-Nov-09 10:33}, +# tags: [ nsf, nx, finance, economy ] +# } \ No newline at end of file Index: library/mongodb/tests/nx-mongo.test =================================================================== diff -u --- library/mongodb/tests/nx-mongo.test (revision 0) +++ library/mongodb/tests/nx-mongo.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,125 @@ +# -*- tcl -*- +# +# This is an example how to use the nx mongo mapping. We show here +# single class mapped to the mongo db with sing and multivalued +# scalars together with some querying options. +# +# Gustaf Neumann fecit, April 2011 +# +package require nx::mongo +package require nx::test +#nsf::configure debug 2 + +# Establish connection to the database +? {::nx::mongo::db connect -db "tutorial"} mongo:0 + +# Make sure, we start always from scratch + +nx::mongo::db remove tutorial.persons {} +if {[::mongo::count [::nx::mongo::db cget -mongoConn] tutorial.persons {}] > 0} { + # when we create a capped colletion, we have to use "drop collection" to get rid of it. + nx::mongo::db drop collection persons +} + +# +# Create the application class "Person" +# +? { + nx::mongo::Class create Person { + :index name + + :property name:required + :property projects:0..n {set :incremental 1} + :property age:integer + } +} ::Person + +# +# Insert a tuple to the database via creating an object, saving and +# destroying it: +# +? { nsf::is object [set p [Person new -name Gustaf -projects {nsf nx nxmongo} -age 53]]} 1 +? { nx::mongo::db is_oid [$p save]} 1 +? { $p destroy; nsf::is object $p} 0 + + +# +# The insert operation of above can be achieved with less typing via +# the conveniance method "insert": +# +? { nx::mongo::db is_oid [Person insert -name Stefan -projects {nsf nx}]} 1 +? { nx::mongo::db is_oid [Person insert -name Joe -projects abc -age 23]} 1 +? { nx::mongo::db is_oid [Person insert -name Franz -projects {gtat annobackend abc} -age 29]} 1 + +# +# Quick check of the results: count all persons and count the persons +# named Gustaf +# +? {Person count} 4 +? {Person count -cond {name = Gustaf}} 1 + +# +# Lookup a single Person, create an instance of the object ... +# +? {nsf::is object [set p [Person find first -cond {name = Gustaf}]]} 1 +#puts [$p serialize] +# +# ... change the age, add an project, and save it. +# +? {$p configure -age 55} "" +? {$p projects add xowiki} "xowiki nsf nx nxmongo" +? {nx::mongo::db is_oid [$p save]} 1 +? {$p destroy; nsf::is object $p} 0 + +# +# Lookup a single Person and create a named object +# +? {Person find first -instance p2 -cond {name = Gustaf}} ::p2 +? {lsort [p2 info vars]} "_id age name projects" +? {p2 destroy; nsf::is object p2} 0 + +# +# Test a few queries based on the user-friendly query language defined +# for the class objects. +# +puts "\nProject members of nsf:" +? {llength [set persons [Person find all -cond {projects = nsf}]]} 2 +? {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 +? {lsort [lmap p $persons {$p cget -name}]} "Franz Gustaf Stefan" + +puts "\nProject members working on both nsf and nxmongo:" +? {llength [set persons [Person find all -cond {projects all {nsf nxmongo}}]]} 1 +? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" + +puts "\nAll Persons sorted by name (ascending):" +? {llength [set persons [Person find all -orderby name]]} 4 +? {lmap p $persons {$p cget -name}} "Franz Gustaf Joe Stefan" + +puts "\nMembers of Projects != 'abc' nsf sorted by name desc and age:" +? {llength [set persons [Person find all -cond {projects != "abc"} -orderby {{name desc} age}]]} 2 +? {lmap p $persons {$p cget -name}} "Stefan Gustaf" + +puts "\nFind persons age > 30:" +? {llength [set persons [Person find all -cond {age > 30}]]} 1 +? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" + + +# +# Define a special find method for "Person" named "oldies" by +# extending the query interface (add sub-method to ensemble). +# +Person public object method "find oldies" {} { + return [:find all -cond {age > 30}] +} + +# +# Use the special find method +# +puts "\nFind oldies:" +? {llength [set persons [Person find oldies]]} 1 +? {lsort [lmap p $persons {$p cget -name}]} "Gustaf" + + Index: library/mongodb/tests/nx-reference-many.test =================================================================== diff -u --- library/mongodb/tests/nx-reference-many.test (revision 0) +++ library/mongodb/tests/nx-reference-many.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,164 @@ +# -*- tcl -*- +# +# This is an introductory example how to use the nx mongo mapping for +# referencing some objects. We use here an example of a Group having +# a (possible compound) users as members. +# +# Gustaf Neumann fecit, May 2011 +# +package require nx::mongo +package require nx::test + +# Establish connection to the database +? {::nx::mongo::db connect -db "tutorial"} mongo:0 + +# Make sure, we start always from scratch +nx::mongo::db drop collection groups +nx::mongo::db drop collection members + +###################################################################### +# The first approach to implement references simply as multivalued +# attributes. This is just feasible in cases, where the user has just +# a name and not more attributes. +# +? {nx::mongo::Class create Group { + :property name + :property members:0..n +}} ::Group + +# Insert entry with the schema of ::Group into the database: +? { nx::mongo::db is_oid [Group insert -name "grp1" -members {gustaf stefan}]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set g [Group find first -cond {name = "grp1"}]]} 1 +? {$g cget -members} "gustaf stefan" + +###################################################################### +# The second approach to implement references to other objects via an +# property pointing to the object ids of other objects. This is +# similar to the classical datbase approach. When the object is +# fetched, the application developer has to care about +# fetching/dereferencing the referenced objects. +# +? {nx::mongo::Class create Member { + :property name +}} ::Member +? {nx::mongo::Class create Group { + :property name + :property members:0..n +}} ::Group + +? {nx::mongo::db is_oid [set id1 [Member insert -name gustaf]]} 1 +? {nx::mongo::db is_oid [set id2 [Member insert -name stefan]]} 1 +? {nx::mongo::db is_oid [Group insert -name "grp2" -members [list $id1 $id2]]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set g [Group find first -cond {name = "grp2"}]]} 1 + +# Obtain the objects with the oids contained in the group +? {llength [set members [Member find all -cond [list _id in [$g cget -members]]]]} 2 +? {lsort [lmap m $members {$m cget -name}]} "gustaf stefan" + + +###################################################################### +# The third approach is to embed the objects in the referencing +# document. This might be feasible when the values of the embedded +# objects seldomly change, When the containing object (the posting) is +# loaded, the appropriate object structure is created automatically. +# +? {nx::mongo::Class create Member { + :property name +}} ::Member +? {nx::mongo::Class create Group { + :property name + :property members:embedded,type=::Member,0..n +}} ::Group + +? {nx::mongo::db is_oid [Group insert -name "grp3" \ + -members [list \ + [Member new -name gustaf] \ + [Member new -name stefan]]]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set g [Group find first -cond {name = "grp3"}]]} 1 +? {lsort [lmap m [$g cget -members] {$m cget -name}]} "gustaf stefan" + + +###################################################################### +# The fourth approach is to use mongo db-refs for referencing. This +# is similar to approach two, but provides support for dereferencing +# and maintaining the reference lists. +# +? {nx::mongo::Class create Member { + :property name +}} ::Member +? {nx::mongo::Class create Group { + :property name + :property members:reference,type=::Member,0..n +}} ::Group + +# +# Currently, the mongo c-driver does not allow to add DBRefs, since +# it refuses to accept field names with leading '$'. So we skip this +# version for the time being. +# +? {nx::mongo::db is_oid [Group insert -name "grp4" \ + -members [list \ + [Member new -name gustaf1] \ + [Member new -name stefan2]]]} 1 +# Retrieve the entry from the database: +? {nsf::is object [set g [Group find first -cond {name = "grp4"}]]} 1 +? {lsort [lmap m [$g cget -members] {$m cget -name}]} "gustaf1 stefan2" + +puts stderr "\nContent of collection groups:" +Group show +puts stderr "\nContent of collection members:" +Member show + + +###################################################################### +# Output +###################################################################### +# Content of collection groups: +# { +# _id: 51fa2ea113760b0000000000, +# name: grp1, +# members: [ gustaf, stefan ] +# }, { +# _id: 51fa2ea113760b0000000003, +# name: grp2, +# members: [ 51fa2ea113760b0000000001, 51fa2ea113760b0000000002 ] +# }, { +# _id: 51fa2ea113760b0000000004, +# name: grp3, +# members: [ { +# name: gustaf }, { +# name: stefan } ] +# }, { +# _id: 51fa2ea113760b0000000007, +# name: grp4, +# members: [ { +# $ref: members, +# $id: 51fa2ea113760b0000000005, +# $db: tutorial }, { +# $ref: members, +# $id: 51fa2ea113760b0000000006, +# $db: tutorial } ] +# } +# +# Content of collection members: +# { +# _id: 51fa2ea113760b0000000001, +# name: gustaf +# }, { +# _id: 51fa2ea113760b0000000002, +# name: stefan +# }, { +# _id: 51fa2ea113760b0000000005, +# name: gustaf1 +# }, { +# _id: 51fa2ea113760b0000000006, +# name: stefan2 +# } + + Index: library/mongodb/tests/nx-reference-one.test =================================================================== diff -u --- library/mongodb/tests/nx-reference-one.test (revision 0) +++ library/mongodb/tests/nx-reference-one.test (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -0,0 +1,146 @@ +# -*- tcl -*- +# +# This is an introductory example how to use the nx mongo mapping for +# referencing some object. We use here an example of an Posting having +# a single (possible compound) user as originator. All example work +# the same way as well with with multivalued attributes. +# +# Gustaf Neumann fecit, May 2011 +# +package require nx::mongo +package require nx::test + +# Establish connection to the database +? {::nx::mongo::db connect -db "tutorial"} mongo:0 + +# Make sure, we start always from scratch +nx::mongo::db drop collection users +nx::mongo::db drop collection posts + + +###################################################################### +# The first approach to implement references simply as an property. +# This is just feasible in cases, where the user has just a name and +# not more attributes. +# +? {nx::mongo::Class create Post { + :property title + :property user +}} ::Post + +# Insert entry with the schema of ::Post into the database: +? {nx::mongo::db is_oid [Post insert -title "Hello trivial World" -user smith] } 1 + +# Retrieve the entry from the database: +? {nsf::is object [set p [Post find first -cond {title = "Hello trivial World"}]]} 1 +? {$p cget -user} smith +? {$p destroy; nsf::is object $p} 0 + +###################################################################### +# The second approach to implement references to other objects via an +# property pointing to the object id of an other object. This is the +# classical datbase approach. When the object is fetched, the +# application developer has to care about fetching/dereferencing the +# referenced object. +# +? {nx::mongo::Class create User { + :property name +}} ::User +? {nx::mongo::Class create Post { + :property title + :property user_id +}} ::Post + +# The method "insert" returns the object id of the newly created +# object. We can use this value as a reference in the Post. +? {nx::mongo::db is_oid [set oid [User insert -name Smith]]} 1 +? {nx::mongo::db is_oid [Post insert -title "Hello simple World" -user_id $oid]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set p [Post find first -cond {title = "Hello simple World"}]]} 1 +? {nsf::is object [set u [User find first -cond [list _id = [$p cget -user_id]]]]} 1 +? {$u cget -name} "Smith" + +###################################################################### +# The third approach is to embed the object in the referencing +# document. This might be feasible when the values of the embedded +# objects seldomly change, When the containing object (the Post +# instance) is loaded, the appropriate object structure is created +# automatically. +# +? {nx::mongo::Class create User { + :property name +}} ::User +? {nx::mongo::Class create Post { + :property title + :property user:embedded,type=::User +}} ::Post + +? {nx::mongo::db is_oid [Post insert -title "Hello embedded World" -user [User new -name Smith]]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set p [Post find first -cond {title = "Hello embedded World"}]]} 1 +? {[$p cget -user] cget -name} "Smith" + +###################################################################### +# The fourth approach is to use mongo db-refs for referencing. This +# is similar to approach two, but provides support for dereferencing +# and maintaining the reference lists. +# +? {nx::mongo::Class create User { + :property name +}} ::User +? {nx::mongo::Class create Post { + :property title + :property user:reference,type=::User +}} ::Post + +? {nx::mongo::db is_oid [Post insert -title "Hello referenced World" -user [User new -name SmithR]]} 1 + +# Retrieve the entry from the database: +? {nsf::is object [set p [Post find first -cond {title = "Hello referenced World"}]]} 1 +? {[$p cget -user] cget -name} SmithR + + +puts stderr "\nContent of the collection posts:" +Post show + +puts stderr "\nContent of the collection users:" +User show +###################################################################### +# Output +###################################################################### + +# Content of the collection posts: +# Content of the collection posts: +# { +# _id: 51fa2f29cb562e0000000000, +# title: {Hello trivial World}, +# user: smith +# }, { +# _id: 51fa2f29cb562e0000000002, +# title: {Hello simple World}, +# user_id: 51fa2f29cb562e0000000001 +# }, { +# _id: 51fa2f29cb562e0000000003, +# title: {Hello embedded World}, +# user: { +# name: Smith } +# }, { +# _id: 51fa2f29cb562e0000000005, +# title: {Hello referenced World}, +# user: { +# $ref: users, +# $id: 51fa2f29cb562e0000000004, +# $db: tutorial } +# } +# +# Content of the collection users: +# { +# _id: 51fa2f29cb562e0000000001, +# name: Smith +# }, { +# _id: 51fa2f29cb562e0000000004, +# name: SmithR +# } +# Index: tests/summary.tcl =================================================================== diff -u -r583bf72dec328676cdf9598a7f38295b2d770df5 -r5c3834b15078b31970db26d0c65030ed1f66b18d --- tests/summary.tcl (.../summary.tcl) (revision 583bf72dec328676cdf9598a7f38295b2d770df5) +++ tests/summary.tcl (.../summary.tcl) (revision 5c3834b15078b31970db26d0c65030ed1f66b18d) @@ -4,6 +4,7 @@ # end of the regression test. It aggreates the content of the test log # provided via arg "-testlog". +array set opt {-title ""} array set opt $::argv if {[info exists opt(-testlog)]} { @@ -20,13 +21,12 @@ } } - puts "\nRegression Test Summary:" + puts "\nRegression Test Summary of $opt(-title):" puts "\tEnvironment: Tcl $tcl_patchLevel, OS $tcl_platform(os) $tcl_platform(osVersion)\ machine $tcl_platform(machine) threaded [info exists tcl_platform(threaded)]." puts "\tNSF performed $tests tests in $files files, success $success, failures $failures in [expr {$ms / 1000.0}] seconds" if {$failures == 0} { - puts "\tCongratulations, NSF [package require nsf], NX [package require nx], and\ - XOTcl [package require XOTcl 2] work fine in your environment." + puts "\tCongratulations, all tests of $opt(-title) passed in your installation of NSF [package req nsf]" } puts "" }