Skip to content
Newer
Older
100644 403 lines (323 sloc) 9.47 KB
f078a4d add support for specifying BSON types
neomantra@gmail.com authored
1 #include <iostream>
2 #include <client/dbclient.h>
3
4 extern "C" {
5 #include <lua.h>
6 #include <lauxlib.h>
7 #include <lualib.h>
8
9 #if !defined(LUA_VERSION_NUM) || (LUA_VERSION_NUM < 501)
10 #include <compat-5.1.h>
11 #endif
12 };
13
14 #include "common.h"
15
16 using namespace mongo;
17
41c68de * Finish GridFS support
nrich@ii.net authored
18 void push_bsontype_table(lua_State* L, mongo::BSONType bsontype);
19 extern const char *bson_name(int type);
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
20 extern void lua_to_bson(lua_State *L, int stackpos, BSONObj &obj);
21 extern void bson_to_lua(lua_State *L, const BSONObj &obj);
f078a4d add support for specifying BSON types
neomantra@gmail.com authored
22
23 static int bson_type_Date(lua_State *L) {
24 push_bsontype_table(L, mongo::Date);
25 lua_pushvalue(L, 1);
26 lua_rawseti(L, -2, 1); // t[1] = function arg #1
27 return 1;
28 }
29
30 static int bson_type_Timestamp(lua_State*L) {
31 push_bsontype_table(L, mongo::Timestamp);
32 // no arg
33 return 1;
34 }
35
36 static int bson_type_RegEx(lua_State *L) {
37 push_bsontype_table(L, mongo::RegEx);
38 lua_pushvalue(L, 1);
39 lua_rawseti(L, -2, 1); // t[1] = function arg #1
40 lua_pushvalue(L, 2);
41 lua_rawseti(L, -2, 2); // set t[2] = function arg #2
42 return 1;
43 }
44
45 static int bson_type_NumberInt(lua_State *L) {
46 push_bsontype_table(L, mongo::NumberInt);
47 lua_pushvalue(L, 1);
48 lua_rawseti(L, -2, 1); // t[1] = function arg #1
49 return 1;
50 }
51
1105ff0 Added NumberLong (64-bit) support.
neomantra authored
52 static int bson_type_NumberLong(lua_State *L) {
53 push_bsontype_table(L, mongo::NumberLong);
54 lua_pushvalue(L, 1);
55 lua_rawseti(L, -2, 1); // t[1] = function arg #1
56 return 1;
57 }
58
f078a4d add support for specifying BSON types
neomantra@gmail.com authored
59 static int bson_type_Symbol(lua_State *L) {
60 push_bsontype_table(L, mongo::Symbol);
61 lua_pushvalue(L, 1);
62 lua_rawseti(L, -2, 1); // t[1] = function arg #1
63 return 1;
64 }
65
32b8cc8 * Add better support for the db connection object
nrich@ii.net authored
66 static int bson_type_ObjectID(lua_State *L) {
8ce988d @mwild1 mongo.ObjectID(): Initialize with generated OID if no input was given.
authored
67 if(lua_gettop(L) == 0)
68 lua_pushstring(L, mongo::OID::gen().toString().data());
b048100 Make OID a BSON type
nrich@ii.net authored
69 push_bsontype_table(L, mongo::jstOID);
70 lua_pushvalue(L, 1);
71 lua_rawseti(L, -2, 1); // t[1] = function arg #1
72 return 1;
73 }
74
32756cf *Handle 'arrays' better
nrich@ii.net authored
75 static int bson_type_NULL(lua_State *L) {
76 push_bsontype_table(L, mongo::jstNULL);
77 // no arg
668f223 Cleaned up whitespace (spaces only)
neomantra authored
78 return 1;
32756cf *Handle 'arrays' better
nrich@ii.net authored
79 }
80
41c68de * Finish GridFS support
nrich@ii.net authored
81 static int integer_value(lua_State *L) {
82 int n = lua_gettop(L);
83 int returncount = 1;
84
85 lua_rawgeti(L, 1, 1);
86
668f223 Cleaned up whitespace (spaces only)
neomantra authored
87 if (n > 1) {
88 lua_pushinteger(L, luaL_checkint(L, 2));
89 lua_rawseti(L, 1, 1);
90 returncount = 0;
41c68de * Finish GridFS support
nrich@ii.net authored
91 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
92 lua_pushinteger(L, luaL_checkint(L, -1));
41c68de * Finish GridFS support
nrich@ii.net authored
93 }
94
95 return returncount;
96 }
97
98 static int number_value(lua_State *L) {
99 int n = lua_gettop(L);
100 int returncount = 1;
101
102 lua_rawgeti(L, 1, 1);
103
668f223 Cleaned up whitespace (spaces only)
neomantra authored
104 if (n > 1) {
105 lua_pushnumber(L, luaL_checknumber(L, 2));
106 lua_rawseti(L, 1, 1);
107 returncount = 0;
41c68de * Finish GridFS support
nrich@ii.net authored
108 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
109 lua_pushnumber(L, luaL_checknumber(L, -1));
41c68de * Finish GridFS support
nrich@ii.net authored
110 }
111
112 return returncount;
113 }
114
115 static int string_value(lua_State *L) {
116 int n = lua_gettop(L);
117 int returncount = 1;
118
119 lua_rawgeti(L, 1, 1);
120
668f223 Cleaned up whitespace (spaces only)
neomantra authored
121 if (n > 1) {
122 lua_pushstring(L, luaL_checkstring(L, 2));
123 lua_rawseti(L, 1, 1);
124 returncount = 0;
41c68de * Finish GridFS support
nrich@ii.net authored
125 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
126 lua_pushstring(L, luaL_checkstring(L, -1));
41c68de * Finish GridFS support
nrich@ii.net authored
127 }
128
129 return returncount;
130 }
131
32756cf *Handle 'arrays' better
nrich@ii.net authored
132 static int null_value(lua_State *L) {
133 lua_pushnil(L);
134
135 return 1;
136 }
137
138
41c68de * Finish GridFS support
nrich@ii.net authored
139 static int stringpair_value(lua_State *L) {
140 int n = lua_gettop(L);
141 int returncount = 2;
142
143 lua_rawgeti(L, 1, 1);
144 lua_rawgeti(L, 1, 2);
145
668f223 Cleaned up whitespace (spaces only)
neomantra authored
146 if (n > 1) {
147 lua_pushstring(L, luaL_checkstring(L, 2));
148 lua_rawseti(L, 1, 1);
149 lua_pushstring(L, luaL_checkstring(L, 3));
150 lua_rawseti(L, 1, 2);
151 returncount = 0;
41c68de * Finish GridFS support
nrich@ii.net authored
152 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
153 lua_pushstring(L, luaL_checkstring(L, -2));
154 lua_pushstring(L, luaL_checkstring(L, -2));
41c68de * Finish GridFS support
nrich@ii.net authored
155 }
156
157 return returncount;
158 }
159
160 static int generic_tostring(lua_State *L) {
161 lua_rawgeti(L, 1, 1);
162
163 lua_pushstring(L, luaL_optstring(L, -1, "nil"));
164
165 return 1;
166 }
167
ed332df Improved tostring for int64-based numeric values.
neomantra authored
168 static int longlong_tostring(lua_State *L) {
169 lua_rawgeti(L, 1, 1);
170 lua_Number num = lua_tonumber(L, -1);
171
172 char numstr[64];
173 int len = snprintf(numstr, 64, "%.f", num);
174
175 lua_pushlstring(L, numstr, len);
176
177 return 1;
178 }
179
41c68de * Finish GridFS support
nrich@ii.net authored
180 static int date_tostring(lua_State *L) {
181 char datestr[64];
182
183 lua_rawgeti(L, 1, 1);
184
185 time_t t = (time_t)(lua_tonumber(L, -1)/1000);
186
187 #if defined(_WIN32)
188 ctime_s(datestr, 64, &t);
189 #else
190 ctime_r(&t,datestr);
191 #endif
192
193 datestr[24] = 0; // don't want the \n
194
195 lua_pushstring(L, datestr);
196
197 return 1;
198 }
199
200 static int regex_tostring(lua_State *L) {
201 lua_rawgeti(L, 1, 1);
202 lua_rawgeti(L, 1, 2);
203
204 lua_pushfstring(L, "/%s/%s", lua_tostring(L, -2), lua_tostring(L, -1));
205
206 return 1;
207 }
208
32756cf *Handle 'arrays' better
nrich@ii.net authored
209 static int null_tostring(lua_State *L) {
210 lua_pushstring(L, "NULL");
211
212 return 1;
213 }
214
41c68de * Finish GridFS support
nrich@ii.net authored
215 // TODO:
216 // all of this should be in Lua so it can get JIT wins
217 // bind the bson typeids
218 // each type could have its cached metatable (from registry)
219
220 // all these types are represented as tables
221 // the metatable entry __bsontype dictates the type
222 // the t[1] represents the object itself, with some types using other fields
223
224 void push_bsontype_table(lua_State* L, mongo::BSONType bsontype) {
225 lua_newtable(L);
226 lua_newtable(L);
227
228 lua_pushstring(L, "__bsontype");
229 lua_pushinteger(L, bsontype);
230 lua_settable(L, -3);
231
232 lua_pushstring(L, "__call");
233 switch(bsontype) {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
234 case mongo::NumberInt:
235 lua_pushcfunction(L, integer_value);
236 break;
1105ff0 Added NumberLong (64-bit) support.
neomantra authored
237 case mongo::NumberLong:
668f223 Cleaned up whitespace (spaces only)
neomantra authored
238 case mongo::Date:
239 case mongo::Timestamp:
240 lua_pushcfunction(L, number_value);
241 break;
242 case mongo::Symbol:
243 case mongo::jstOID:
244 lua_pushcfunction(L, string_value);
245 break;
246 case mongo::RegEx:
247 lua_pushcfunction(L, stringpair_value);
248 break;
249 case mongo::jstNULL:
250 lua_pushcfunction(L, null_value);
251 break;
41c68de * Finish GridFS support
nrich@ii.net authored
252 }
253 lua_settable(L, -3);
254
255 lua_pushstring(L, "__tostring");
256 switch(bsontype) {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
257 case mongo::NumberInt:
258 case mongo::Symbol:
259 case mongo::jstOID:
260 lua_pushcfunction(L, generic_tostring);
261 break;
ed332df Improved tostring for int64-based numeric values.
neomantra authored
262 case mongo::Timestamp:
263 case mongo::NumberLong:
264 lua_pushcfunction(L, longlong_tostring);
265 break;
668f223 Cleaned up whitespace (spaces only)
neomantra authored
266 case mongo::Date:
267 lua_pushcfunction(L, date_tostring);
268 break;
269 case mongo::RegEx:
270 lua_pushcfunction(L, regex_tostring);
271 break;
272 case mongo::jstNULL:
273 lua_pushcfunction(L, null_tostring);
274 break;
41c68de * Finish GridFS support
nrich@ii.net authored
275 }
276 lua_settable(L, -3);
277
278 lua_setmetatable(L, -2);
279 }
280
281 /*
282 * typename = mongo.type(obj)
283 */
284 static int bson_type_name(lua_State *L) {
285 if (lua_istable(L, 1)) {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
286 int bsontype_found = luaL_getmetafield(L, 1, "__bsontype");
41c68de * Finish GridFS support
nrich@ii.net authored
287
668f223 Cleaned up whitespace (spaces only)
neomantra authored
288 if (bsontype_found) {
41c68de * Finish GridFS support
nrich@ii.net authored
289 int bson_type = lua_tointeger(L, -1);
290 lua_pop(L, 1);
291
668f223 Cleaned up whitespace (spaces only)
neomantra authored
292 lua_pushfstring(L, "%s.%s", LUAMONGO_ROOT, bson_name(bson_type));
293 } else {
294 lua_pushstring(L, luaL_typename(L, 1));
295 }
41c68de * Finish GridFS support
nrich@ii.net authored
296 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
297 lua_pushstring(L, luaL_typename(L, 1));
41c68de * Finish GridFS support
nrich@ii.net authored
298 }
299
300 return 1;
301 }
302
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
303 /*
668f223 Cleaned up whitespace (spaces only)
neomantra authored
304 * num = mongo.tonumber(obj)
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
305 */
306 static int bson_tonumber(lua_State *L) {
307 int base = luaL_optint(L, 2, 10);
308 if (base == 10) { /* standard conversion */
668f223 Cleaned up whitespace (spaces only)
neomantra authored
309 luaL_checkany(L, 1);
310 if (lua_isnumber(L, 1)) {
311 lua_pushnumber(L, lua_tonumber(L, 1));
312 return 1;
313 } else if (lua_istable(L, 1)) {
314 int bsontype_found = luaL_getmetafield(L, 1, "__bsontype");
315
316 if (bsontype_found) {
317 lua_rawgeti(L, 1, 1);
318
319 if (lua_isnumber(L, -1)) {
320 lua_pushnumber(L, lua_tonumber(L, -1));
321 return 1;
322 }
323
324 lua_pop(L, 1);
325 }
326 }
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
327 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
328 const char *s1 = luaL_checkstring(L, 1);
329 char *s2;
330 unsigned long n;
331 luaL_argcheck(L, 2 <= base && base <= 36, 2, "base out of range");
332 n = strtoul(s1, &s2, base);
333 if (s1 != s2) { /* at least one valid digit? */
334 while (isspace((unsigned char)(*s2))) s2++; /* skip trailing spaces */
335 if (*s2 == '\0') { /* no invalid trailing characters? */
336 lua_pushnumber(L, (lua_Number)n);
337 return 1;
338 }
339 }
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
340 }
341
342 lua_pushnil(L); /* else not a number */
343 return 1;
344 }
345
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
346 static int bson_tojson(lua_State *L) {
347 int resultcount = 1;
348 BSONObj obj;
349
350 if (lua_istable(L, 1)) {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
351 lua_to_bson(L, 1, obj);
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
352
668f223 Cleaned up whitespace (spaces only)
neomantra authored
353 lua_pushstring(L, obj.toString().c_str());
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
354 } else {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
355 lua_pushnil(L);
356 lua_pushfstring(L, "Argument is not a table");
357 resultcount = 2;
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
358 }
359
360 return resultcount;
361 }
362
363 static int bson_fromjson(lua_State *L) {
364 const char *json = luaL_checkstring(L, 1);
365 int resultcount = 1;
366 BSONObj obj;
367
368 try {
668f223 Cleaned up whitespace (spaces only)
neomantra authored
369 bson_to_lua(L, fromjson(json));
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
370 } catch (std::exception &e) {
371 lua_pushnil(L);
372 lua_pushfstring(L, "Error parsing JSON: %s", e.what());
373 resultcount = 2;
374 }
375
32b8cc8 * Add better support for the db connection object
nrich@ii.net authored
376 return resultcount;
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
377 }
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
378
f078a4d add support for specifying BSON types
neomantra@gmail.com authored
379 int mongo_bsontypes_register(lua_State *L) {
380 static const luaL_Reg bsontype_methods[] = {
381 {"Date", bson_type_Date},
382 {"Timestamp", bson_type_Timestamp},
383 {"RegEx", bson_type_RegEx},
384 {"NumberInt", bson_type_NumberInt},
1105ff0 Added NumberLong (64-bit) support.
neomantra authored
385 {"NumberLong", bson_type_NumberLong},
7f16174 fix broken mongo.Symbol registration
neomantra@gmail.com authored
386 {"Symbol", bson_type_Symbol},
32b8cc8 * Add better support for the db connection object
nrich@ii.net authored
387 {"ObjectId", bson_type_ObjectID},
32756cf *Handle 'arrays' better
nrich@ii.net authored
388 {"NULL", bson_type_NULL},
6c50993 Add 'mongo.tojson' and 'mongo.fromjson' functions to serialize to/fro…
nrich@ii.net authored
389
668f223 Cleaned up whitespace (spaces only)
neomantra authored
390 // Utils
41c68de * Finish GridFS support
nrich@ii.net authored
391 {"type", bson_type_name},
e42f34b Added mongo.tonumber to return number values for bson types
nrich@ii.net authored
392 {"tonumber", bson_tonumber},
668f223 Cleaned up whitespace (spaces only)
neomantra authored
393 {"tojson", bson_tojson},
394 {"fromjson", bson_fromjson},
f078a4d add support for specifying BSON types
neomantra@gmail.com authored
395 {NULL, NULL}
396 };
397
398 luaL_register(L, LUAMONGO_ROOT, bsontype_methods);
399
400 return 1;
401 }
402
Something went wrong with that request. Please try again.