diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2a1404d --- /dev/null +++ b/.gitignore @@ -0,0 +1,25 @@ +gmon.out + +# Building files # +################## +*.o +*.so + +# Emacs backups # +################# +*~ +\#*\# +.\#* + +# Vim swap # +*.swp +# OS generated files # +###################### +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +Icon? +ehthumbs.db +Thumbs.db diff --git a/Makefile b/Makefile index 65454db..d2d4959 100644 --- a/Makefile +++ b/Makefile @@ -1,52 +1,30 @@ CC= g++ -CFLAGS= -g -O2 -shared -fPIC -I /usr/include/lua5.1/ -I/usr/local/include/mongo/ +CFLAGS= -Wall -g -O2 -shared -fPIC -I/usr/include/mongo `pkg-config --cflags lua5.2` `pkg-config --cflags libmongo-client` AR= ar rcu RANLIB= ranlib RM= rm -f -LIBS=-lmongoclient -lboost_thread -lboost_filesystem +LIBS=`pkg-config --libs lua5.2` -lmongoclient -lssl -lboost_thread -lboost_filesystem OUTLIB=mongo.so LDFLAGS= $(LIBS) -OBJS = main.o mongo_bsontypes.o mongo_dbclient.o mongo_replicaset.o mongo_connection.o mongo_cursor.o mongo_gridfile.o mongo_gridfs.o mongo_gridfschunk.o mongo_query.o utils.o +OBJS = main.o mongo_bsontypes.o mongo_dbclient.o mongo_replicaset.o mongo_connection.o mongo_cursor.o mongo_gridfile.o mongo_gridfs.o mongo_gridfschunk.o mongo_query.o utils.o mongo_cxx_extension.o mongo_gridfilebuilder.o -all: luamongo +UNAME = `uname` +PLAT = DetectOS + +all: $(PLAT) + +DetectOS: + @make $(UNAME) + +Linux: + @make -f Makefile.linux + +Darwin: + @make -f Makefile.macports clean: $(RM) $(OBJS) $(OUTLIB) -luamongo: $(OBJS) - $(CC) $(CFLAGS) $(OBJS) -o $(OUTLIB) $(LDFLAGS) - -echo: - @echo "CC = $(CC)" - @echo "CFLAGS = $(CFLAGS)" - @echo "AR = $(AR)" - @echo "RANLIB = $(RANLIB)" - @echo "RM = $(RM)" - @echo "LDFLAGS = $(LDFLAGS)" - -main.o: main.cpp utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_dbclient.o: mongo_dbclient.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_connection.o: mongo_connection.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_cursor.o: mongo_cursor.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_gridfile.o: mongo_gridfile.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_gridfs.o: mongo_gridfs.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_gridfschunk.o: mongo_gridfschunk.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_query.o: mongo_query.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_replicaset.o: mongo_replicaset.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) -mongo_bsontypes.o: mongo_bsontypes.cpp common.h - $(CC) -c -o $@ $< $(CFLAGS) -utils.o: utils.cpp common.h utils.h - $(CC) -c -o $@ $< $(CFLAGS) - .PHONY: all diff --git a/Makefile.linux b/Makefile.linux new file mode 100644 index 0000000..284e3db --- /dev/null +++ b/Makefile.linux @@ -0,0 +1,56 @@ +CC= g++ +CFLAGS= -Wall -g -O2 -shared -fPIC -I/usr/include/mongo `pkg-config --cflags lua5.2` `pkg-config --cflags libmongo-client` +AR= ar rcu +RANLIB= ranlib +RM= rm -f +LIBS=`pkg-config --libs lua5.2` -lmongoclient -lssl -lboost_thread -lboost_filesystem +OUTLIB=mongo.so + +LDFLAGS= $(LIBS) + +OBJS = main.o mongo_bsontypes.o mongo_dbclient.o mongo_replicaset.o mongo_connection.o mongo_cursor.o mongo_gridfile.o mongo_gridfs.o mongo_gridfschunk.o mongo_query.o utils.o mongo_cxx_extension.o mongo_gridfilebuilder.o + +all: luamongo + +clean: + $(RM) $(OBJS) $(OUTLIB) + +luamongo: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $(OUTLIB) $(LDFLAGS) + +echo: + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "RM = $(RM)" + @echo "LDFLAGS = $(LDFLAGS)" + +main.o: main.cpp utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_dbclient.o: mongo_dbclient.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_connection.o: mongo_connection.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_cursor.o: mongo_cursor.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfile.o: mongo_gridfile.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfs.o: mongo_gridfs.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfschunk.o: mongo_gridfschunk.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_query.o: mongo_query.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_replicaset.o: mongo_replicaset.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_bsontypes.o: mongo_bsontypes.cpp common.h + $(CC) -c -o $@ $< $(CFLAGS) +utils.o: utils.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_cxx_extension.o: mongo_cxx_extension.cpp mongo_cxx_extension.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfilebuilder.o: mongo_gridfilebuilder.cpp mongo_cxx_extension.h common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) + +.PHONY: all diff --git a/Makefile.macports b/Makefile.macports new file mode 100644 index 0000000..64a2947 --- /dev/null +++ b/Makefile.macports @@ -0,0 +1,56 @@ +CC= g++ +CFLAGS= -Wall -g -O2 -fPIC `pkg-config --cflags "lua >= 5.2"` -I/opt/local/include/mongo/ +AR= ar rcu +RANLIB= ranlib +RM= rm -f +LIBS=`pkg-config --libs "lua >= 5.2"` -lmongoclient -lssl -lboost_thread-mt -lboost_filesystem-mt -flat_namespace -bundle -L/opt/local/lib -rdynamic +OUTLIB=mongo.so + +LDFLAGS= $(LIBS) + +OBJS = main.o mongo_bsontypes.o mongo_dbclient.o mongo_replicaset.o mongo_connection.o mongo_cursor.o mongo_gridfile.o mongo_gridfs.o mongo_gridfschunk.o mongo_query.o utils.o mongo_cxx_extension.o mongo_gridfilebuilder.o + +all: luamongo + +clean: + $(RM) $(OBJS) $(OUTLIB) + +luamongo: $(OBJS) + $(CC) $(CFLAGS) $(OBJS) -o $(OUTLIB) $(LDFLAGS) + +echo: + @echo "CC = $(CC)" + @echo "CFLAGS = $(CFLAGS)" + @echo "AR = $(AR)" + @echo "RANLIB = $(RANLIB)" + @echo "RM = $(RM)" + @echo "LDFLAGS = $(LDFLAGS)" + +main.o: main.cpp utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_dbclient.o: mongo_dbclient.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_connection.o: mongo_connection.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_cursor.o: mongo_cursor.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfile.o: mongo_gridfile.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfs.o: mongo_gridfs.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfschunk.o: mongo_gridfschunk.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_query.o: mongo_query.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_replicaset.o: mongo_replicaset.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_bsontypes.o: mongo_bsontypes.cpp common.h + $(CC) -c -o $@ $< $(CFLAGS) +utils.o: utils.cpp common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_cxx_extension.o: mongo_cxx_extension.cpp mongo_cxx_extension.h + $(CC) -c -o $@ $< $(CFLAGS) +mongo_gridfilebuilder.o: mongo_gridfilebuilder.cpp mongo_cxx_extension.h common.h utils.h + $(CC) -c -o $@ $< $(CFLAGS) + +.PHONY: all diff --git a/README.md b/README.md index c2ab938..dcbe7df 100644 --- a/README.md +++ b/README.md @@ -16,13 +16,13 @@ ## Support -Submit issues to the moai github site. +Submit issues to the pakozm github site. There is a Google Groups mailing list. ## Example - require('mongo') + local mongo = require('mongo') -- Create a connection object local db = assert(mongo.Connection.New()) @@ -54,9 +54,9 @@ There is a Google Groups maili ## How It Works -luamongo is a Lua library that wraps the mongodb C++ API. +luamongo is a Lua library that wraps the mongodb C++ API. -The current implementation does not give you raw access to the BSON objects. BSON objects are passed to the API using a Lua table or a JSON string representation. Every returned BSON document is fully marshalled to a Lua table. +The current implementation does not give you raw access to the BSON objects. BSON objects are passed to the API using a Lua table or a JSON string representation. Every returned BSON document is fully marshalled to a Lua table. ## Installing @@ -66,5 +66,5 @@ luarocks can be used to install luamongo. ## History -This project was forked from the luamongo project on googlecode. +This project was forked from the luamongo project on GitHub. diff --git a/common.h b/common.h index 8582cb1..bc081b1 100644 --- a/common.h +++ b/common.h @@ -1,14 +1,20 @@ -#define LUAMONGO_ROOT "mongo" -#define LUAMONGO_CONNECTION "mongo.Connection" -#define LUAMONGO_REPLICASET "mongo.ReplicaSet" -#define LUAMONGO_CURSOR "mongo.Cursor" -#define LUAMONGO_QUERY "mongo.Query" -#define LUAMONGO_GRIDFS "mongo.GridFS" -#define LUAMONGO_GRIDFILE "mongo.GridFile" -#define LUAMONGO_GRIDFSCHUNK "mongo.GridFSChunk" +#define LUAMONGO_NAME "mongo" +#define LUAMONGO_NAME_STRING "_NAME" +#define LUAMONGO_VERSION "0.4" +#define LUAMONGO_VERSION_STRING "_VERSION" + +#define LUAMONGO_ROOT "mongo" +#define LUAMONGO_CONNECTION "Connection" +#define LUAMONGO_REPLICASET "ReplicaSet" +#define LUAMONGO_CURSOR "Cursor" +#define LUAMONGO_QUERY "Query" +#define LUAMONGO_GRIDFS "GridFS" +#define LUAMONGO_GRIDFILE "GridFile" +#define LUAMONGO_GRIDFSCHUNK "GridFSChunk" +#define LUAMONGO_GRIDFILEBUILDER "GridFileBuilder" // not an actual class, pseudo-base for error messages -#define LUAMONGO_DBCLIENT "mongo.DBClient" +#define LUAMONGO_DBCLIENT "DBClient" #define LUAMONGO_ERR_CONNECTION_FAILED "Connection failed: %s" #define LUAMONGO_ERR_REPLICASET_FAILED "ReplicaSet.New failed: %s" diff --git a/debian/control b/debian/control index c139ea0..448855d 100644 --- a/debian/control +++ b/debian/control @@ -1,16 +1,16 @@ Source: luamongo Section: database Priority: optional -Maintainer: Evan Wies -Build-Depends: debhelper (>= 7.0.50), liblua5.1-0-dev, +Maintainer: Francisco Zamora-Martinez +Build-Depends: debhelper (>= 7.0.50), liblua5.2-dev, mongodb (>= 1.6) | mongodb-stable (>= 1.6) | mongodb-unstable (>= 1.6) | mongodb-snapshot (>= 1.6) | libmongoclient-dev (>= 1.6) | mongodb-dev (>= 1.6), libboost-thread-dev (>= 1.40), libboost-filesystem-dev (>= 1.40) Standards-Version: 3.8.4 -Homepage: http://code.google.com/p/luamongo/ +Homepage: https://github.com/pabloromeu/luamongo -Package: liblua5.1-mongo +Package: liblua5.2-mongo Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, lua5.1 +Depends: ${shlibs:Depends}, ${misc:Depends}, lua5.2 Description: Lua driver for MongoDB Lua (http://www.lua.org) driver for MongoDB (http://www.mongodb.org). diff --git a/debian/install b/debian/install index 45ababb..f5580d9 100644 --- a/debian/install +++ b/debian/install @@ -1 +1 @@ -mongo.so usr/lib/lua/5.1 \ No newline at end of file +mongo.so usr/lib/lua/5.2 \ No newline at end of file diff --git a/main.cpp b/main.cpp index e98a51e..95e9865 100644 --- a/main.cpp +++ b/main.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com) * Copyright (c) 2009 Neil Richardson (nrich@iinet.net.au) * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -20,19 +21,8 @@ * IN THE SOFTWARE. */ -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include #include - #include "utils.h" #include "common.h" @@ -44,6 +34,7 @@ extern int mongo_query_register(lua_State *L); extern int mongo_gridfs_register(lua_State *L); extern int mongo_gridfile_register(lua_State *L); extern int mongo_gridfschunk_register(lua_State *L); +extern int mongo_gridfilebuilder_register(lua_State *L); /* * @@ -54,21 +45,52 @@ extern int mongo_gridfschunk_register(lua_State *L); extern "C" { LM_EXPORT int luaopen_mongo(lua_State *L) { + // bsontypes is the root table mongo_bsontypes_register(L); + + // LUAMONGO_CONNECTION mongo_connection_register(L); + lua_setfield(L, -2, LUAMONGO_CONNECTION); + + // LUAMONGO_REPLICASET mongo_replicaset_register(L); + lua_setfield(L, -2, LUAMONGO_REPLICASET); + + // LUAMONGO_CURSOR mongo_cursor_register(L); + lua_setfield(L, -2, LUAMONGO_CURSOR); + + // LUAMONGO_QUERY mongo_query_register(L); - + lua_setfield(L, -2, LUAMONGO_QUERY); + + // LUAMONGO_GRIDFS mongo_gridfs_register(L); + lua_setfield(L, -2, LUAMONGO_GRIDFS); + + // LUAMONGO_GRIDFILE mongo_gridfile_register(L); + lua_setfield(L, -2, LUAMONGO_GRIDFILE); + + // LUAMONGO_GRIDFSCHUNK mongo_gridfschunk_register(L); + lua_setfield(L, -2, LUAMONGO_GRIDFSCHUNK); + + // LUAMONGO_GRIDFILEBUILDER + mongo_gridfilebuilder_register(L); + lua_setfield(L, -2, LUAMONGO_GRIDFILEBUILDER); /* * push the created table to the top of the stack * so "mongo = require('mongo')" works */ - lua_getglobal(L, LUAMONGO_ROOT); + // lua_getglobal(L, LUAMONGO_ROOT); + + // push the version number and module name + lua_pushstring(L, LUAMONGO_NAME); + lua_setfield(L, -2, LUAMONGO_NAME_STRING); + lua_pushstring(L, LUAMONGO_VERSION); + lua_setfield(L, -2, LUAMONGO_VERSION_STRING); return 1; } diff --git a/mongo_bsontypes.cpp b/mongo_bsontypes.cpp index 617eddc..db931c0 100644 --- a/mongo_bsontypes.cpp +++ b/mongo_bsontypes.cpp @@ -1,16 +1,6 @@ #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - +#include "utils.h" #include "common.h" using namespace mongo; @@ -233,6 +223,8 @@ void push_bsontype_table(lua_State* L, mongo::BSONType bsontype) { case mongo::jstNULL: lua_pushcfunction(L, null_value); break; + default: + ; } lua_settable(L, -3); @@ -257,6 +249,8 @@ void push_bsontype_table(lua_State* L, mongo::BSONType bsontype) { case mongo::jstNULL: lua_pushcfunction(L, null_tostring); break; + default: + ; } lua_settable(L, -3); @@ -381,8 +375,9 @@ int mongo_bsontypes_register(lua_State *L) { {NULL, NULL} }; - luaL_register(L, LUAMONGO_ROOT, bsontype_methods); - + //luaL_register(L, LUAMONGO_ROOT, bsontype_methods); + luaL_newlib(L, bsontype_methods); + return 1; } diff --git a/mongo_connection.cpp b/mongo_connection.cpp index 1d60826..4bfa82a 100644 --- a/mongo_connection.cpp +++ b/mongo_connection.cpp @@ -1,15 +1,5 @@ #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - +#include "utils.h" #include "common.h" using namespace mongo; @@ -115,8 +105,10 @@ int mongo_connection_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_CONNECTION); - luaL_register(L, NULL, dbclient_methods); - luaL_register(L, NULL, connection_methods); + //luaL_register(L, NULL, dbclient_methods); + luaL_setfuncs(L, dbclient_methods, 0); + //luaL_register(L, NULL, connection_methods); + luaL_setfuncs(L, connection_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -125,8 +117,11 @@ int mongo_connection_register(lua_State *L) { lua_pushcfunction(L, connection_tostring); lua_setfield(L, -2, "__tostring"); - - luaL_register(L, LUAMONGO_CONNECTION, connection_class_methods); + + lua_pop(L,1); + + //luaL_register(L, LUAMONGO_CONNECTION, connection_class_methods); + luaL_newlib(L, connection_class_methods); return 1; } diff --git a/mongo_cursor.cpp b/mongo_cursor.cpp index e430088..c384f35 100644 --- a/mongo_cursor.cpp +++ b/mongo_cursor.cpp @@ -1,16 +1,5 @@ #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" @@ -192,7 +181,8 @@ int mongo_cursor_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_CURSOR); - luaL_register(L, 0, cursor_methods); + //luaL_register(L, 0, cursor_methods); + luaL_setfuncs(L, cursor_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -201,8 +191,11 @@ int mongo_cursor_register(lua_State *L) { lua_pushcfunction(L, cursor_tostring); lua_setfield(L, -2, "__tostring"); - - luaL_register(L, LUAMONGO_CURSOR, cursor_class_methods); + + lua_pop(L,1); + + //luaL_register(L, LUAMONGO_CURSOR, cursor_class_methods); + luaL_newlib(L, cursor_class_methods); return 1; } diff --git a/mongo_cxx_extension.cpp b/mongo_cxx_extension.cpp new file mode 100644 index 0000000..bda2852 --- /dev/null +++ b/mongo_cxx_extension.cpp @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include "mongo_cxx_extension.h" + +namespace mongo_cxx_extension { + + using namespace mongo; + + using std::ios; + using std::ofstream; + using std::ostream; + using std::string; + using std::min; + + GridFileBuilder::GridFileBuilder(DBClientBase *client, + const string &dbName, + unsigned int chunkSize, + const string& prefix) : + _client(client), _dbName(dbName), _prefix(prefix), _chunkSize(chunkSize), + _current_chunk(0), _pending_data(NULL), _pending_data_size(0), + _file_length(0) { + _chunkNS = _dbName + "." + _prefix + ".chunks"; + _filesNS = _dbName + "." + _prefix + ".files"; + OID id; + id.init(); + _file_id = BSON("_id" << id); + // forces to build the gridFS collections + GridFS aux(*client, dbName, prefix); + } + + GridFileBuilder::~GridFileBuilder() { + delete[] _pending_data; + } + + const char *GridFileBuilder::privateAppendChunk(const char *data, + size_t length, + bool pending_insert) { + size_t chunk_len; + char const * const end = data + length; + while (data < end) { + chunk_len = min(_chunkSize, (size_t)(end-data)); + // the last chunk needs to be stored as pending_data + if (chunk_len < _chunkSize && !pending_insert) break; + /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */ + BSONObjBuilder b; + b.appendAs( _file_id["_id"] , "files_id" ); + b.append( "n" , _current_chunk ); + b.appendBinData( "data" , chunk_len, BinDataGeneral, data ); + BSONObj chunk_data = b.obj(); + /************************************************************************/ + ++_current_chunk; + _client->insert( _chunkNS.c_str(), chunk_data ); + data += chunk_len; + _file_length += chunk_len; + } + return data; + } + + void GridFileBuilder::privateAppendPendingData() { + if (_pending_data_size > 0) { + privateAppendChunk(_pending_data, _pending_data_size, true); + delete[] _pending_data; + _pending_data_size = 0; + _pending_data = NULL; + } + } + + void GridFileBuilder::appendChunk(const char *data, size_t length) { + if (length == 0) return; + // check if there are pending data + if (_pending_data != NULL) { + size_t total_size = _pending_data_size + length; + size_t size = min(_chunkSize, total_size) - _pending_data_size; + memcpy(_pending_data + _pending_data_size, data, size*sizeof(char)); + _pending_data_size += size; + // CHECK _pending_data_size <= _chunkSize + if (_pending_data_size == _chunkSize) { + privateAppendPendingData(); + appendChunk(data + size, length - size); + } + } + else { + char const * const end = data + length; + // split data in _chunkSize blocks, and store as pending the last block if + // necessary + data = privateAppendChunk(data, length); + // process pending data if necessary + if (data != end) { + if (_pending_data_size == 0) _pending_data = new char[_chunkSize]; + size_t size = (size_t)(end-data); + memcpy(_pending_data+_pending_data_size, data, size*sizeof(char)); + _pending_data_size += size; + } + } + } + + BSONObj GridFileBuilder::buildFile(const string &name, + const string& content_type) { + privateAppendPendingData(); + + /* from gridfs.cpp at https://github.com/mongodb/mongo-cxx-driver/blob/legacy/src/mongo/client/gridfs.cpp */ + + // Wait for any pending writebacks to finish + BSONObj errObj = _client->getLastErrorDetailed(); + uassert( 16428, + str::stream() << "Error storing GridFS chunk for file: " << name + << ", error: " << errObj, + DBClientWithCommands::getLastErrorString(errObj) == "" ); + + BSONObj res; + if ( ! _client->runCommand( _dbName.c_str() , + BSON( "filemd5" << _file_id << "root" << _prefix ) , + res ) ) + throw UserException( 9008 , "filemd5 failed" ); + + BSONObjBuilder file; + file << "_id" << _file_id["_id"] + << "filename" << name + << "chunkSize" << (unsigned int)_chunkSize + << "uploadDate" << DATENOW + << "md5" << res["md5"] + ; + + if (_file_length < 1024*1024*1024) { // 2^30 + file << "length" << (int) _file_length; + } + else { + file << "length" << (long long) _file_length; + } + + if (!content_type.empty()) + file << "contentType" << content_type; + + BSONObj ret = file.obj(); + _client->insert(_filesNS.c_str(), ret); + + // resets the object + _current_chunk = 0; + _pending_data = NULL; + _pending_data_size = 0; + _file_length = 0; + OID id; + id.init(); + _file_id = BSON("_id" << id); + + return ret; + } + +} diff --git a/mongo_cxx_extension.h b/mongo_cxx_extension.h new file mode 100644 index 0000000..94a7ba5 --- /dev/null +++ b/mongo_cxx_extension.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef MONGO_CXX_EXTENSION +#define MONGO_CXX_EXTENSION + +#include +#include + +namespace mongo_cxx_extension { + + const unsigned int DEFAULT_CHUNK_SIZE = 256*1024; + + // FIXME: client pointer is keep, review Lua binding in order to avoid + // unexpected garbage collection of DBClientBase + class GridFileBuilder { + public: + /** + * @param client - db connection + * @param dbName - root database name + * @param chunkSize - size of chunks + * @param prefix - if you want your data somewhere besides .fs + */ + GridFileBuilder(mongo::DBClientBase *client, const std::string &dbName, + unsigned int chunkSize = DEFAULT_CHUNK_SIZE, + const std::string& prefix = "fs"); + ~GridFileBuilder(); + // chunks are splitted in as many as necessary chunkSize blocks; sizes not + // multiple of chunkSize will copy remaining data at pending_data pointer + void appendChunk(const char *data, size_t length); + // buildFile will destroy this builder, not allowing to insert more data + mongo::BSONObj buildFile(const std::string &name, + const std::string& contentType=""); + + private: + mongo::DBClientBase *_client; + std::string _dbName; + std::string _prefix; + std::string _chunkNS; + std::string _filesNS; + size_t _chunkSize; + unsigned int _current_chunk; + mongo::BSONObj _file_id; + char *_pending_data; // NULL or pointer with _chunkSize space + size_t _pending_data_size; + mongo::gridfs_offset _file_length; + + const char *privateAppendChunk(const char *data, size_t length, + bool pending_insert = false); + void privateAppendPendingData(); + }; +} + +#endif // MONGO_CXX_EXTENSION diff --git a/mongo_dbclient.cpp b/mongo_dbclient.cpp index b8548e1..acc9a63 100644 --- a/mongo_dbclient.cpp +++ b/mongo_dbclient.cpp @@ -1,14 +1,4 @@ #include - -extern "C" { -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" @@ -28,7 +18,7 @@ DBClientBase* userdata_to_dbclient(lua_State *L, int stackpos) // adapted from http://www.lua.org/source/5.1/lauxlib.c.html#luaL_checkudata void *ud = lua_touserdata(L, stackpos); if (ud == NULL) - luaL_typerror(L, stackpos, "userdata"); + luaL_typeerror(L, stackpos, "userdata"); // try Connection lua_getfield(L, LUA_REGISTRYINDEX, LUAMONGO_CONNECTION); @@ -60,7 +50,7 @@ DBClientBase* userdata_to_dbclient(lua_State *L, int stackpos) else lua_pop(L, 1); - luaL_typerror(L, stackpos, LUAMONGO_DBCLIENT); + luaL_typeerror(L, stackpos, LUAMONGO_DBCLIENT); return NULL; // should never get here } @@ -91,7 +81,8 @@ static int dbclient_ensure_index(lua_State *L) { } } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "ensure_index", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "ensure_index", e.what()); return 2; } catch (const char *err) { lua_pushboolean(L, 0); @@ -129,10 +120,10 @@ static int dbclient_auth(lua_State *L) { const char *password = luaL_checkstring(L, -1); lua_getfield(L, 2, "digestPassword"); bool digestPassword = lua_isnil(L, -1) ? true : lua_toboolean(L, -1); - lua_pop(L, 4); - + std::string errmsg; bool success = dbclient->auth(dbname, username, password, errmsg, digestPassword); + lua_pop(L, 4); if (!success) { lua_pushnil(L); lua_pushfstring(L, LUAMONGO_ERR_CONNECTION_FAILED, errmsg.c_str()); @@ -236,7 +227,7 @@ static int dbclient_insert_batch(lua_State *L) { try { std::vector vdata; - size_t tlen = lua_objlen(L, 3) + 1; + size_t tlen = lua_rawlen(L, 3) + 1; for (size_t i = 1; i < tlen; ++i) { vdata.push_back(BSONObj()); lua_rawgeti(L, 3, i); @@ -263,6 +254,7 @@ static int dbclient_insert_batch(lua_State *L) { */ static int dbclient_query(lua_State *L) { int n = lua_gettop(L); + UNUSED_VARIABLE(n); DBClientBase *dbclient = userdata_to_dbclient(L, 1); const char *ns = luaL_checkstring(L, 2); @@ -331,6 +323,7 @@ static int dbclient_query(lua_State *L) { */ static int dbclient_find_one(lua_State *L) { int n = lua_gettop(L); + UNUSED_VARIABLE(n); DBClientBase *dbclient = userdata_to_dbclient(L, 1); const char *ns = luaL_checkstring(L, 2); @@ -509,7 +502,8 @@ static int dbclient_drop_collection(lua_State *L) { dbclient->dropCollection(ns); } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "drop_collection", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "drop_collection", e.what()); return 2; } @@ -540,7 +534,8 @@ static int dbclient_drop_index_by_fields(lua_State *L) { dbclient->dropIndex(ns, keys); } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "drop_index_by_fields", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "drop_index_by_fields", e.what()); return 2; } catch (const char *err) { lua_pushboolean(L, 0); @@ -563,7 +558,8 @@ static int dbclient_drop_index_by_name(lua_State *L) { dbclient->dropIndex(ns, luaL_checkstring(L, 3)); } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "drop_index_by_name", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "drop_index_by_name", e.what()); return 2; } @@ -582,7 +578,8 @@ static int dbclient_drop_indexes(lua_State *L) { dbclient->dropIndexes(ns); } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "drop_indexes", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "drop_indexes", e.what()); return 2; } @@ -617,7 +614,8 @@ static int dbclient_eval(lua_State *L) { } } catch (std::exception &e) { lua_pushnil(L); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "eval", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "eval", e.what()); return 2; } catch (const char *err) { lua_pushnil(L); @@ -630,7 +628,8 @@ static int dbclient_eval(lua_State *L) { if (!res) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "eval", info["errmsg"].str().c_str()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "eval", + info["errmsg"].str().c_str()); return 2; } @@ -680,7 +679,8 @@ static int dbclient_gen_index_name(lua_State *L) { } } catch (std::exception &e) { lua_pushnil(L); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "gen_index_name", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "gen_index_name", e.what()); return 2; } catch (const char *err) { lua_pushnil(L); @@ -707,7 +707,8 @@ static int dbclient_get_indexes(lua_State *L) { return 2; } - DBClientCursor **cursor = (DBClientCursor **)lua_newuserdata(L, sizeof(DBClientCursor *)); + DBClientCursor **cursor = + (DBClientCursor **)lua_newuserdata(L, sizeof(DBClientCursor *)); *cursor = autocursor.get(); autocursor.release(); @@ -718,14 +719,16 @@ static int dbclient_get_indexes(lua_State *L) { } /* - * res,err = db:mapreduce(jsmapfunc, jsreducefunc[, query[, output]]) + * res,err = db:mapreduce(ns, jsmapfunc, jsreducefunc[, query[, output]]) */ static int dbclient_mapreduce(lua_State *L) { DBClientBase *dbclient = userdata_to_dbclient(L, 1); const char *ns = luaL_checkstring(L, 2); const char *jsmapfunc = luaL_checkstring(L, 3); const char *jsreducefunc = luaL_checkstring(L, 4); - + const char *output = NULL; + if (!lua_isnoneornil(L, 6)) output = luaL_checkstring(L, 6); + BSONObj query; if (!lua_isnoneornil(L, 5)) { try { @@ -740,7 +743,8 @@ static int dbclient_mapreduce(lua_State *L) { } } catch (std::exception &e) { lua_pushnil(L); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "mapreduce", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "mapreduce", e.what()); return 2; } catch (const char *err) { lua_pushnil(L); @@ -748,10 +752,12 @@ static int dbclient_mapreduce(lua_State *L) { return 2; } } - - const char *output = luaL_optstring(L, 6, ""); - - BSONObj res = dbclient->mapreduce(ns, jsmapfunc, jsreducefunc, query, output); + + BSONObj res; + if (output == NULL) + res = dbclient->mapreduce(ns, jsmapfunc, jsreducefunc, query); + else + res = dbclient->mapreduce(ns, jsmapfunc, jsreducefunc, query, output); bson_to_lua(L, res); @@ -769,7 +775,8 @@ static int dbclient_reindex(lua_State *L) { dbclient->reIndex(ns); } catch (std::exception &e) { lua_pushboolean(L, 0); - lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, "reindex", e.what()); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "reindex", e.what()); return 2; } @@ -849,6 +856,60 @@ static int dbclient_run_command(lua_State *L) { } } +/* + * res,err = db:get_dbnames() + */ +static int dbclient_get_dbnames(lua_State *L) { + DBClientBase *dbclient = userdata_to_dbclient(L, 1); + try { + list dbs = dbclient->getDatabaseNames(); + lua_newtable(L); + int i=1; + for (list::iterator it=dbs.begin(); it!=dbs.end(); ++it, ++i) { + lua_pushnumber(L,i); + lua_pushstring(L,it->c_str()); + lua_settable(L,-3); + } + return 1; + } catch (std::exception &e) { + lua_pushboolean(L, 0); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "get_dbnames", e.what()); + return 2; + } catch (const char *err) { + lua_pushboolean(L, 0); + lua_pushstring(L, err); + return 2; + } +} + +/* + * res,err = db:get_collections() + */ +static int dbclient_get_collections(lua_State *L) { + DBClientBase *dbclient = userdata_to_dbclient(L, 1); + const char *ns = luaL_checkstring(L, 2); + try { + list dbs = dbclient->getCollectionNames(ns); + lua_newtable(L); + int i=1; + for (list::iterator it=dbs.begin(); it!=dbs.end(); ++it, ++i) { + lua_pushnumber(L,i); + lua_pushstring(L,it->c_str()); + lua_settable(L,-3); + } + return 1; + } catch (std::exception &e) { + lua_pushboolean(L, 0); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_CONNECTION, + "get_collections", e.what()); + return 2; + } catch (const char *err) { + lua_pushboolean(L, 0); + lua_pushstring(L, err); + return 2; + } +} // Method registration table for DBClients extern const luaL_Reg dbclient_methods[] = { @@ -877,6 +938,8 @@ extern const luaL_Reg dbclient_methods[] = { {"reset_index_cache", dbclient_reset_index_cache}, {"run_command", dbclient_run_command}, {"update", dbclient_update}, + {"get_dbnames", dbclient_get_dbnames}, + {"get_collections", dbclient_get_collections}, {NULL, NULL} }; diff --git a/mongo_gridfile.cpp b/mongo_gridfile.cpp index af54b85..506444e 100644 --- a/mongo_gridfile.cpp +++ b/mongo_gridfile.cpp @@ -1,17 +1,6 @@ #include #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" @@ -260,7 +249,8 @@ int mongo_gridfile_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_GRIDFILE); - luaL_register(L, 0, gridfile_methods); + //luaL_register(L, 0, gridfile_methods); + luaL_setfuncs(L, gridfile_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -273,7 +263,10 @@ int mongo_gridfile_register(lua_State *L) { lua_pushcfunction(L, gridfile_content_length); lua_setfield(L, -2, "__len"); - luaL_register(L, LUAMONGO_GRIDFILE, gridfile_class_methods); + lua_pop(L,1); + + //luaL_register(L, LUAMONGO_GRIDFILE, gridfile_class_methods); + luaL_newlib(L, gridfile_class_methods); return 1; } diff --git a/mongo_gridfilebuilder.cpp b/mongo_gridfilebuilder.cpp new file mode 100644 index 0000000..1132939 --- /dev/null +++ b/mongo_gridfilebuilder.cpp @@ -0,0 +1,169 @@ +#include +#include +#include "mongo_cxx_extension.h" +#include "utils.h" +#include "common.h" + +// FIXME: client pointer is keep, review Lua binding in order to avoid +// unexpected garbage collection of DBClientBase + +using namespace mongo; + +extern void lua_to_bson(lua_State *L, int stackpos, BSONObj &obj); +extern void bson_to_lua(lua_State *L, const BSONObj &obj); +extern int gridfile_create(lua_State *L, GridFile gf); +extern DBClientBase* userdata_to_dbclient(lua_State *L, int stackpos); + +namespace { + inline mongo_cxx_extension::GridFileBuilder* userdata_to_gridfilebuilder(lua_State* L, + int index) { + void *ud = 0; + + ud = luaL_checkudata(L, index, LUAMONGO_GRIDFILEBUILDER); + mongo_cxx_extension::GridFileBuilder *gridfilebuilder; + gridfilebuilder = *((mongo_cxx_extension::GridFileBuilder **)ud); + + return gridfilebuilder; + } +} // anonymous namespace + +/* + * builder, err = mongo.GridFileBuilder.New(connection, dbname[, chunksize[, prefix]]) + */ +static int gridfilebuilder_new(lua_State *L) { + int n = lua_gettop(L); + int resultcount = 1; + + try { + DBClientBase *connection = userdata_to_dbclient(L, 1); + const char *dbname = lua_tostring(L, 2); + + mongo_cxx_extension::GridFileBuilder **builder; + builder = (mongo_cxx_extension::GridFileBuilder **) + lua_newuserdata(L, sizeof(mongo_cxx_extension::GridFileBuilder *)); + + if (n >= 4) { + unsigned int chunksize = static_cast(luaL_checkint(L, 3)); + const char *prefix = luaL_checkstring(L, 4); + + *builder = new mongo_cxx_extension::GridFileBuilder(connection, + dbname, + chunksize, + prefix); + } else if (n == 3) { + unsigned int chunksize = static_cast(luaL_checkint(L, 3)); + + *builder = new mongo_cxx_extension::GridFileBuilder(connection, + dbname, chunksize); + } else { + *builder = new mongo_cxx_extension::GridFileBuilder(connection, dbname); + } + + luaL_getmetatable(L, LUAMONGO_GRIDFILEBUILDER); + lua_setmetatable(L, -2); + } catch (std::exception &e) { + lua_pushnil(L); + lua_pushfstring(L, LUAMONGO_ERR_CONNECTION_FAILED, e.what()); + resultcount = 2; + } + + return resultcount; +} + +/* + * ok, err = builder:append(data_string) + */ +static int gridfilebuilder_append(lua_State *L) { + mongo_cxx_extension::GridFileBuilder *builder; + builder = userdata_to_gridfilebuilder(L, 1); + int resultcount = 1; + try { + size_t length = 0; + const char *data = luaL_checklstring(L, 2, &length); + builder->appendChunk(data, length); + lua_pushboolean(L, 1); + } catch (std::exception &e) { + lua_pushnil(L); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_GRIDFILEBUILDER, + "append", e.what()); + resultcount = 2; + } + return resultcount; +} + +/* + * bson, err = builder:build(remote_file[, content_type]) + */ +static int gridfilebuilder_build(lua_State *L) { + int resultcount = 1; + mongo_cxx_extension::GridFileBuilder *builder; + builder = userdata_to_gridfilebuilder(L, 1); + const char *remote = luaL_checkstring(L, 2); + const char *content_type = luaL_optstring(L, 3, ""); + try { + BSONObj res = builder->buildFile(remote, content_type); + bson_to_lua(L, res); + } catch (std::exception &e) { + lua_pushnil(L); + lua_pushfstring(L, LUAMONGO_ERR_CALLING, LUAMONGO_GRIDFILEBUILDER, + "build", e.what()); + resultcount = 2; + } + return resultcount; +} + +/* + * __gc + */ +static int gridfilebuilder_gc(lua_State *L) { + mongo_cxx_extension::GridFileBuilder *builder; + builder = userdata_to_gridfilebuilder(L, 1); + + delete builder; + + return 0; +} + +/* + * __tostring + */ +static int gridfilebuilder_tostring(lua_State *L) { + mongo_cxx_extension::GridFileBuilder *builder; + builder = userdata_to_gridfilebuilder(L, 1); + + lua_pushfstring(L, "%s: %p", LUAMONGO_GRIDFILEBUILDER, builder); + + return 1; +} + +int mongo_gridfilebuilder_register(lua_State *L) { + static const luaL_Reg gridfilebuilder_methods[] = { + {"append", gridfilebuilder_append}, + {"write", gridfilebuilder_append}, + {"build", gridfilebuilder_build}, + {NULL, NULL} + }; + + static const luaL_Reg gridfilebuilder_class_methods[] = { + {"New", gridfilebuilder_new}, + {NULL, NULL} + }; + + luaL_newmetatable(L, LUAMONGO_GRIDFILEBUILDER); + //luaL_register(L, 0, gridfs_methods); + luaL_setfuncs(L, gridfilebuilder_methods, 0); + lua_pushvalue(L,-1); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, gridfilebuilder_gc); + lua_setfield(L, -2, "__gc"); + + lua_pushcfunction(L, gridfilebuilder_tostring); + lua_setfield(L, -2, "__tostring"); + + lua_pop(L,1); + + luaL_newlib(L, gridfilebuilder_class_methods); + + return 1; +} diff --git a/mongo_gridfs.cpp b/mongo_gridfs.cpp index 177d037..7c5a53d 100644 --- a/mongo_gridfs.cpp +++ b/mongo_gridfs.cpp @@ -1,20 +1,12 @@ #include #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" +// FIXME: GridFS pointer is keep in GridFile objects, review Lua binding in +// order to avoid unexpected garbage collection of GridFS pointer + using namespace mongo; extern void lua_to_bson(lua_State *L, int stackpos, BSONObj &obj); @@ -98,19 +90,23 @@ static int gridfs_find_file(lua_State *L) { } - - - - /* - * cursor,err = gridfs:list() + * cursor,err = gridfs:list([lua_table or json_str]) */ static int gridfs_list(lua_State *L) { GridFS *gridfs = userdata_to_gridfs(L, 1); - auto_ptr autocursor = gridfs->list(); + BSONObj query; + int type = lua_type(L, 2); + if (type == LUA_TSTRING) { + const char *jsonstr = luaL_checkstring(L, 2); + query = fromjson(jsonstr); + } else if (type == LUA_TTABLE) { + lua_to_bson(L, 2, query); + } + auto_ptr autocursor = gridfs->list(query); - if (!autocursor.get()) { + if (!autocursor.get()){ lua_pushnil(L); lua_pushstring(L, LUAMONGO_ERR_CONNECTION_LOST); return 2; @@ -149,7 +145,7 @@ static int gridfs_remove_file(lua_State *L) { } /* - * gridfile, err = gridfs:store_file(filename[, remote_file], content_type]]) + * bson, err = gridfs:store_file(filename[, remote_file[, content_type]]) */ static int gridfs_store_file(lua_State *L) { int resultcount = 1; @@ -174,7 +170,7 @@ static int gridfs_store_file(lua_State *L) { /* - * gridfile, err = gridfs:store_data(data[, remote_file], content_type]]) + * bson, err = gridfs:store_data(data[, remote_file], content_type]]) * puts the file represented by data into the db */ static int gridfs_store_data(lua_State *L) { @@ -199,7 +195,6 @@ static int gridfs_store_data(lua_State *L) { return resultcount; } - /* * __gc */ @@ -238,7 +233,8 @@ int mongo_gridfs_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_GRIDFS); - luaL_register(L, 0, gridfs_methods); + //luaL_register(L, 0, gridfs_methods); + luaL_setfuncs(L, gridfs_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -247,8 +243,11 @@ int mongo_gridfs_register(lua_State *L) { lua_pushcfunction(L, gridfs_tostring); lua_setfield(L, -2, "__tostring"); + + lua_pop(L,1); - luaL_register(L, LUAMONGO_GRIDFS, gridfs_class_methods); + //luaL_register(L, LUAMONGO_GRIDFS, gridfs_class_methods); + luaL_newlib(L, gridfs_class_methods); return 1; } diff --git a/mongo_gridfschunk.cpp b/mongo_gridfschunk.cpp index 527404f..eb836ab 100644 --- a/mongo_gridfschunk.cpp +++ b/mongo_gridfschunk.cpp @@ -1,17 +1,6 @@ #include #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" @@ -86,8 +75,13 @@ int mongo_gridfschunk_register(lua_State *L) { {NULL, NULL} }; + static const luaL_Reg gridfschunk_class_methods[] = { + {NULL, NULL} + }; + luaL_newmetatable(L, LUAMONGO_GRIDFSCHUNK); - luaL_register(L, 0, gridfschunk_methods); + //luaL_register(L, 0, gridfschunk_methods); + luaL_setfuncs(L, gridfschunk_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -100,7 +94,10 @@ int mongo_gridfschunk_register(lua_State *L) { lua_pushcfunction(L, gridfschunk_len); lua_setfield(L, -2, "__len"); + lua_pop(L,1); + //luaL_register(L, LUAMONGO_GRIDFSCHUNK, gridfschunk_class_methods); + luaL_newlib(L, gridfschunk_class_methods); return 1; } diff --git a/mongo_query.cpp b/mongo_query.cpp index 21ab11b..28c2650 100644 --- a/mongo_query.cpp +++ b/mongo_query.cpp @@ -1,16 +1,5 @@ #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" @@ -344,7 +333,8 @@ int mongo_query_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_QUERY); - luaL_register(L, 0, query_methods); + //luaL_register(L, 0, query_methods); + luaL_setfuncs(L, query_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -353,8 +343,11 @@ int mongo_query_register(lua_State *L) { lua_pushcfunction(L, query_tostring); lua_setfield(L, -2, "__tostring"); - - luaL_register(L, LUAMONGO_QUERY, query_class_methods); + + lua_pop(L,1); + + //luaL_register(L, LUAMONGO_QUERY, query_class_methods); + luaL_newlib(L, query_class_methods); lua_pushstring(L, "Options"); lua_newtable(L); diff --git a/mongo_replicaset.cpp b/mongo_replicaset.cpp index 923a0a1..28c9c56 100644 --- a/mongo_replicaset.cpp +++ b/mongo_replicaset.cpp @@ -1,15 +1,5 @@ #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - +#include "utils.h" #include "common.h" using namespace mongo; @@ -114,8 +104,10 @@ int mongo_replicaset_register(lua_State *L) { }; luaL_newmetatable(L, LUAMONGO_REPLICASET); - luaL_register(L, NULL, dbclient_methods); - luaL_register(L, NULL, replicaset_methods); + //luaL_register(L, NULL, dbclient_methods); + luaL_setfuncs(L, dbclient_methods, 0); + //luaL_register(L, NULL, replicaset_methods); + luaL_setfuncs(L, replicaset_methods, 0); lua_pushvalue(L,-1); lua_setfield(L, -2, "__index"); @@ -124,8 +116,11 @@ int mongo_replicaset_register(lua_State *L) { lua_pushcfunction(L, replicaset_tostring); lua_setfield(L, -2, "__tostring"); - - luaL_register(L, LUAMONGO_REPLICASET, replicaset_class_methods); + + lua_pop(L,1); + + //luaL_register(L, LUAMONGO_REPLICASET, replicaset_class_methods); + luaL_newlib(L, replicaset_class_methods); return 1; } diff --git a/tests/connection.lua b/tests/connection.lua index ffe44d9..9733e9c 100755 --- a/tests/connection.lua +++ b/tests/connection.lua @@ -7,11 +7,10 @@ -- TEST_USER (nil, no auth will be done) -- TEST_PASS ('') -require 'mongo' -require 'os' +local mongo = require 'mongo' +local os = require 'os' -require 'tests/lunity' -module( 'LUAMONGO_TEST_CONNECTION', lunity ) +local lunity = require 'tests.lunity' function setup() test_server = os.getenv('TEST_SERVER') or 'localhost' @@ -66,5 +65,6 @@ function test_ReplicaSet() assertEqual( result.b, data.b ) end - -runTests() +local t = {setup=setup, test=test_ReplicaSet, teardown=teardown} +lunity(t) +t.runTests() diff --git a/tests/lunity.lua b/tests/lunity.lua index 3bc0248..de08a5c 100644 --- a/tests/lunity.lua +++ b/tests/lunity.lua @@ -46,11 +46,8 @@ local setmetatable=setmetatable local _G=_G -module( 'lunity' ) -VERSION = "0.9" - -local lunity = _M +local lunity = { _VERSION = "0.9", _NAME="lunity" } setmetatable( lunity, { __index = _G, __call = function( self, testSuite ) @@ -363,4 +360,6 @@ function __runAllTests( testSuite, options ) end io.stdout:flush() -end \ No newline at end of file +end + +return lunity diff --git a/tests/replicaset.lua b/tests/replicaset.lua index 236104c..5a7d99b 100755 --- a/tests/replicaset.lua +++ b/tests/replicaset.lua @@ -7,11 +7,10 @@ -- TEST_USER (nil, no auth will be done) -- TEST_PASS ('') -require 'mongo' -require 'os' +local mongo = require 'mongo' +local os = require 'os' -require 'tests/lunity' -module( 'LUAMONGO_TEST_REPLICASET', lunity ) +local lunity = require 'tests.lunity' function setup() test_server = os.getenv('TEST_SERVER') or 'localhost' @@ -66,5 +65,6 @@ function test_ReplicaSet() assertEqual( result.b, data.b ) end - -runTests() +local t = {setup=setup, test=test_ReplicaSet, teardown=teardown} +lunity(t) +t.runTests() diff --git a/utils.cpp b/utils.cpp index 2f8556c..13127d7 100644 --- a/utils.cpp +++ b/utils.cpp @@ -1,16 +1,5 @@ #include #include - -extern "C" { -#include -#include -#include - -#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501) -#include -#endif -}; - #include "utils.h" #include "common.h" #include @@ -365,3 +354,11 @@ const char *bson_name(int type) { return name; } + +/* this was removed in Lua 5.2 */ +LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname) { + const char *msg; + msg = lua_pushfstring(L, "%s expected, got %s", + tname, lua_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} diff --git a/utils.h b/utils.h index a626d4a..0d47c25 100644 --- a/utils.h +++ b/utils.h @@ -1,4 +1,5 @@ /* + * Copyright (c) 2014 Francisco Zamora-Martinez (pakozm@gmail.com) * Copyright (c) 2007-2009 Neil Richardson (nrich@iinet.net.au) * * Permission is hereby granted, free of charge, to any person obtaining a copy @@ -29,6 +30,21 @@ * */ +extern "C" { +#include +#include +#include + +#if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 502) +#error "Needs Lua 5.2 or greater" +#endif +}; + +#define UNUSED_VARIABLE(x) (void)(x) + +/* this was removed in Lua 5.2 */ +LUALIB_API int luaL_typeerror (lua_State *L, int narg, const char *tname); + #define LUA_PUSH_ATTRIB_INT(n, v) \ lua_pushstring(L, n); \ lua_pushinteger(L, v); \