PageRenderTime 46ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/Falcon-0.9.6.8/modules/native/mongodb/mongodb_ext.cpp

#
C++ | 1047 lines | 640 code | 152 blank | 255 comment | 143 complexity | 3a9eaeea6d81aa0c5e420628e6480598 MD5 | raw file
Possible License(s): BSD-3-Clause, MPL-2.0-no-copyleft-exception, GPL-2.0
  1. /*
  2. * Falcon MongoDB - Extension
  3. */
  4. #include "mongodb_ext.h"
  5. #include "mongodb_mod.h"
  6. #include "mongodb_srv.h"
  7. #include "mongodb_st.h"
  8. #include <falcon/engine.h>
  9. #include <falcon/vm.h>
  10. #include <stdio.h>//debug..
  11. extern Falcon::MongoDBService theMongoDBService;
  12. /*#
  13. @beginmodule mongodb
  14. */
  15. namespace Falcon
  16. {
  17. namespace Ext
  18. {
  19. /*#
  20. @class MongoDBError
  21. @brief Error generated MongoDB operations.
  22. @optparam code The error code
  23. @optparam desc The description for the error code
  24. @optparam extra Extra information specifying the error conditions.
  25. @from Error( code, desc, extra )
  26. */
  27. FALCON_FUNC MongoDBError_init( VMachine* vm )
  28. {
  29. CoreObject *einst = vm->self().asObject();
  30. if ( einst->getUserData() == 0 )
  31. einst->setUserData( new MongoDBError );
  32. ::Falcon::core::Error_init( vm );
  33. }
  34. /*******************************************************************************
  35. MongoDB class
  36. *******************************************************************************/
  37. /*#
  38. @class MongoDB
  39. @brief Create a client connection to a MongoDB database.
  40. @optparam host default to localhost.
  41. @optparam port default to 27017.
  42. */
  43. FALCON_FUNC MongoDBConnection_init( VMachine* vm )
  44. {
  45. Item* i_host = vm->param( 0 );
  46. Item* i_port = vm->param( 1 );
  47. if ( ( i_host && !i_host->isString() )
  48. || ( i_port && !i_port->isInteger() ) )
  49. {
  50. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  51. .extra( "[S,I]" ) );
  52. }
  53. const char* host;
  54. AutoCString zHost;
  55. if ( i_host )
  56. {
  57. zHost.set( *i_host );
  58. host = zHost.c_str();
  59. }
  60. else
  61. host = "127.0.0.1";
  62. int port = i_port ? i_port->asInteger() : 27017;
  63. MongoDB::Connection* conn = 0;
  64. conn = new MongoDB::Connection( host, port, 0 );
  65. if ( !conn )
  66. {
  67. throw new MongoDBError( ErrorParam( MONGODB_ERR_CREATE_CONN, __LINE__ )
  68. .desc( FAL_STR( _err_create_conn ) ) );
  69. }
  70. CoreObject* self = vm->self().asObjectSafe();
  71. self->setUserData( conn );
  72. vm->retval( self );
  73. }
  74. /*#
  75. @method host MongoDB
  76. @optparam host
  77. @brief When given a parameter, change the host for the next connection attempt. Else return the current host.
  78. @return self (with param) or the current host.
  79. */
  80. FALCON_FUNC MongoDBConnection_host( VMachine* vm )
  81. {
  82. Item* i_host = vm->param( 0 );
  83. if ( i_host && !i_host->isString() )
  84. {
  85. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  86. .extra( "[S]" ) );
  87. }
  88. CoreObject* self = vm->self().asObjectSafe();
  89. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  90. if ( i_host ) // set host
  91. {
  92. AutoCString zHost( *i_host );
  93. conn->hostPort( zHost.c_str() );
  94. vm->retval( self );
  95. }
  96. else // get host
  97. {
  98. String s( conn->host() );
  99. s.bufferize();
  100. vm->retval( s );
  101. }
  102. }
  103. /*#
  104. @method port MongoDB
  105. @optparam port
  106. @brief When given a parameter, change the port for the next connection attempt. Else return the current port.
  107. @return self (with param) or the current port.
  108. */
  109. FALCON_FUNC MongoDBConnection_port( VMachine* vm )
  110. {
  111. Item* i_port = vm->param( 0 );
  112. if ( i_port && !i_port->isInteger() )
  113. {
  114. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  115. .extra( "[I]" ) );
  116. }
  117. CoreObject* self = vm->self().asObjectSafe();
  118. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  119. if ( i_port ) // set port
  120. {
  121. conn->hostPort( 0, i_port->asInteger() );
  122. vm->retval( self );
  123. }
  124. else // get port
  125. {
  126. vm->retval( conn->port() );
  127. }
  128. }
  129. /*#
  130. @method connect MongoDB
  131. @brief Connect or reconnect to MongoDB server.
  132. */
  133. FALCON_FUNC MongoDBConnection_connect( VMachine* vm )
  134. {
  135. CoreObject* self = vm->self().asObjectSafe();
  136. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  137. int ret = conn->connect();
  138. if ( ret != mongo_conn_success )
  139. {
  140. switch ( ret )
  141. {
  142. case -1:
  143. throw new MongoDBError( ErrorParam( MONGODB_ERR_NOMEM, __LINE__ )
  144. .desc( FAL_STR( _err_nomem ) ) );
  145. case mongo_conn_bad_arg:
  146. throw new MongoDBError( ErrorParam( MONGODB_ERR_CONNECT, __LINE__ )
  147. .desc( FAL_STR( _err_connect_bad_arg ) ) );
  148. case mongo_conn_no_socket:
  149. throw new MongoDBError( ErrorParam( MONGODB_ERR_CONNECT, __LINE__ )
  150. .desc( FAL_STR( _err_connect_no_socket ) ) );
  151. case mongo_conn_not_master:
  152. throw new MongoDBError( ErrorParam( MONGODB_ERR_CONNECT, __LINE__ )
  153. .desc( FAL_STR( _err_connect_not_master ) ) );
  154. case mongo_conn_fail:
  155. default:
  156. throw new MongoDBError( ErrorParam( MONGODB_ERR_CONNECT, __LINE__ )
  157. .desc( FAL_STR( _err_connect_fail ) ) );
  158. }
  159. }
  160. }
  161. /*#
  162. @method disconnect MongoDB
  163. @brief Disconnect to MongoDB server.
  164. */
  165. FALCON_FUNC MongoDBConnection_disconnect( VMachine* vm )
  166. {
  167. CoreObject* self = vm->self().asObjectSafe();
  168. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  169. int ret = conn->disconnect();
  170. // we just ignore errors.
  171. //if ( ret ) printf( "Disconnection error (%d)\n", ret );
  172. }
  173. /*#
  174. @method isConnected MongoDB
  175. @brief Checks if the DB is connected.
  176. @return true if connected
  177. */
  178. FALCON_FUNC MongoDBConnection_isConnected( VMachine* vm )
  179. {
  180. CoreObject* self = vm->self().asObjectSafe();
  181. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  182. vm->retval( conn->isConnected() );
  183. }
  184. /*#
  185. @method authenticate MongoDB
  186. @brief Authenticates a user on the DB.
  187. @param db Database
  188. @param user User ID
  189. @param pass Password
  190. @return true if authenticated
  191. */
  192. FALCON_FUNC MongoDBConnection_authenticate( VMachine* vm )
  193. {
  194. Item* i_db = vm->param( 0 );
  195. Item* i_user = vm->param( 1 );
  196. Item* i_pass = vm->param( 2 );
  197. if ( !i_db || !i_db->isString()
  198. || !i_user || !i_user->isString()
  199. || !i_pass || !i_pass->isString() )
  200. {
  201. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  202. .extra( "S,S,S" ) );
  203. }
  204. AutoCString zDB( *i_db );
  205. AutoCString zUser( *i_user );
  206. AutoCString zPass( *i_pass );
  207. CoreObject* self = vm->self().asObjectSafe();
  208. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  209. bool b = conn->authenticate( zDB.c_str(), zUser.c_str(), zPass.c_str() );
  210. vm->retval( b );
  211. }
  212. /*#
  213. @method addUser MongoDB
  214. @brief Adds a user to the DB.
  215. @param db Database
  216. @param user User ID to be added
  217. @param pass Password for the new user.
  218. @return true if user was added
  219. */
  220. FALCON_FUNC MongoDBConnection_addUser( VMachine* vm )
  221. {
  222. Item* i_db = vm->param( 0 );
  223. Item* i_user = vm->param( 1 );
  224. Item* i_pass = vm->param( 2 );
  225. if ( !i_db || !i_db->isString()
  226. || !i_user || !i_user->isString()
  227. || !i_pass || !i_pass->isString() )
  228. {
  229. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  230. .extra( "S,S,S" ) );
  231. }
  232. AutoCString zDB( *i_db );
  233. AutoCString zUser( *i_user );
  234. AutoCString zPass( *i_pass );
  235. CoreObject* self = vm->self().asObjectSafe();
  236. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  237. bool b = conn->addUser( zDB.c_str(), zUser.c_str(), zPass.c_str() );
  238. vm->retval( b );
  239. }
  240. /*#
  241. @method dropDatabase MongoDB
  242. @brief Drops the database.
  243. @param db The database to be dropped
  244. @return true on success
  245. */
  246. FALCON_FUNC MongoDBConnection_dropDatabase( VMachine* vm )
  247. {
  248. Item* i_db = vm->param( 0 );
  249. if ( !i_db || !i_db->isString() )
  250. {
  251. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  252. .extra( "S" ) );
  253. }
  254. AutoCString zDB( *i_db );
  255. CoreObject* self = vm->self().asObjectSafe();
  256. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  257. bool b = conn->dropDatabase( zDB.c_str() );
  258. vm->retval( b );
  259. }
  260. /*#
  261. @method dropCollection MongoDB
  262. @brief Removes a collection from a database.
  263. @param db The database
  264. @param coll The collection to be dropped
  265. @return true on success
  266. */
  267. FALCON_FUNC MongoDBConnection_dropCollection( VMachine* vm )
  268. {
  269. Item* i_db = vm->param( 0 );
  270. Item* i_coll = vm->param( 1 );
  271. if ( !i_db || !i_db->isString()
  272. || !i_coll || !i_coll->isString() )
  273. {
  274. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  275. .extra( "S,S" ) );
  276. }
  277. AutoCString zDB( *i_db );
  278. AutoCString zColl( *i_coll );
  279. CoreObject* self = vm->self().asObjectSafe();
  280. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  281. bool b = conn->dropCollection( zDB.c_str(), zColl.c_str() );
  282. vm->retval( b );
  283. }
  284. /*#
  285. @method insert MongoDB
  286. @brief Inserts an instance.
  287. @param ns namespace
  288. @param bson BSONObj instance, or an array of BSON instances
  289. @return true on success
  290. */
  291. FALCON_FUNC MongoDBConnection_insert( VMachine* vm )
  292. {
  293. Item* i_ns = vm->param( 0 );
  294. Item* i_bobj = vm->param( 1 );
  295. if ( !i_ns || !i_ns->isString()
  296. || !i_bobj
  297. || !( i_bobj->isArray()
  298. || ( i_bobj->isObject() && i_bobj->asObjectSafe()->derivedFrom( "BSON" ) ) ) )
  299. {
  300. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  301. .extra( "S,BSON|A" ) );
  302. }
  303. CoreObject* self = vm->self().asObjectSafe();
  304. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  305. bool b;
  306. if ( i_bobj->isObject() )
  307. {
  308. CoreObject* obj = i_bobj->asObjectSafe();
  309. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( obj->getUserData() );
  310. b = conn->insert( *i_ns->asString(), bobj );
  311. }
  312. else // is array
  313. {
  314. AutoCString zNs( *i_ns );
  315. b = conn->insert( zNs.c_str(), *i_bobj->asArray() );
  316. }
  317. vm->retval( b );
  318. }
  319. /*#
  320. @method update MongoDB
  321. @brief Updates an existing instance.
  322. @param ns namespace
  323. @param cond BSON instance (conditions)
  324. @param op BSON instance (operations)
  325. @optparam upsert (boolean) default true
  326. @optparam multiple (boolean) default true
  327. @return true on success
  328. */
  329. FALCON_FUNC MongoDBConnection_update( VMachine* vm )
  330. {
  331. Item* i_ns = vm->param( 0 );
  332. Item* i_cond = vm->param( 1 );
  333. Item* i_op = vm->param( 2 );
  334. Item* i_upsert = vm->param( 3 );
  335. Item* i_multi = vm->param( 4 );
  336. if ( !i_ns || !i_ns->isString()
  337. || !i_cond || !( i_cond->isObject() && i_cond->asObjectSafe()->derivedFrom( "BSON" ) )
  338. || !i_op || !( i_op->isObject() && i_op->asObjectSafe()->derivedFrom( "BSON" ) )
  339. || ( i_upsert && !i_upsert->isBoolean() )
  340. || ( i_multi && !i_multi->isBoolean() ) )
  341. {
  342. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  343. .extra( "S,BSON,BSON" ) );
  344. }
  345. CoreObject* self = vm->self().asObjectSafe();
  346. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  347. AutoCString zNs( *i_ns );
  348. MongoDB::BSONObj* cond = static_cast<MongoDB::BSONObj*>( i_cond->asObjectSafe()->getUserData() );
  349. MongoDB::BSONObj* op = static_cast<MongoDB::BSONObj*>( i_op->asObjectSafe()->getUserData() );
  350. const bool upsert = i_upsert? i_upsert->asBoolean() : true;
  351. const bool multi = i_multi ? i_multi->asBoolean() : true;
  352. vm->retval( conn->update( zNs.c_str(), cond, op, upsert, multi ) );
  353. }
  354. /*#
  355. @method remove MongoDB
  356. @brief Removes an instance.
  357. @param ns namespace
  358. @param cond BSON instance (conditions)
  359. @return true on success
  360. */
  361. FALCON_FUNC MongoDBConnection_remove( VMachine* vm )
  362. {
  363. Item* i_ns = vm->param( 0 );
  364. Item* i_cond = vm->param( 1 );
  365. if ( !i_ns || !i_ns->isString()
  366. || !i_cond || !( i_cond->isObject() && i_cond->asObjectSafe()->derivedFrom( "BSON" ) ) )
  367. {
  368. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  369. .extra( "S,BSON" ) );
  370. }
  371. CoreObject* self = vm->self().asObjectSafe();
  372. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  373. AutoCString zNs( *i_ns );
  374. MongoDB::BSONObj* cond = static_cast<MongoDB::BSONObj*>( i_cond->asObjectSafe()->getUserData() );
  375. vm->retval( conn->remove( zNs.c_str(), cond ) );
  376. }
  377. /*#
  378. @method findOne MongoDB
  379. @brief Finds an instance.
  380. @param ns namespace
  381. @optparam query BSON instance
  382. @return BSON result or nil
  383. */
  384. FALCON_FUNC MongoDBConnection_findOne( VMachine* vm )
  385. {
  386. Item* i_ns = vm->param( 0 );
  387. Item* i_query = vm->param( 1 );
  388. if ( !i_ns || !i_ns->isString()
  389. || ( i_query && !( i_query->isObject() && i_query->asObjectSafe()->derivedFrom( "BSON" ) ) ) )
  390. {
  391. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  392. .extra( "S,[BSON]" ) );
  393. }
  394. CoreObject* self = vm->self().asObjectSafe();
  395. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  396. AutoCString zNs( *i_ns );
  397. MongoDB::BSONObj* ret = 0;
  398. bool b;
  399. if ( i_query )
  400. {
  401. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( i_query->asObjectSafe()->getUserData() );
  402. b = conn->findOne( zNs.c_str(), bobj, &ret );
  403. }
  404. else
  405. b = conn->findOne( zNs.c_str(), 0, &ret );
  406. if ( b )
  407. {
  408. fassert( ret );
  409. Item* wki = vm->findWKI( "BSON" );
  410. CoreObject* obj = wki->asClass()->createInstance();
  411. fassert( !obj->getUserData() );
  412. obj->setUserData( ret );
  413. vm->retval( obj );
  414. }
  415. else
  416. vm->retnil();
  417. }
  418. /*#
  419. @method find MongoDB
  420. @brief Finds instances corespoding to the given query.
  421. @optparam query BSON instance
  422. @optparam fields BSON instance
  423. @optparam skip default 0
  424. @optparam limit default 0 (all)
  425. @return An array of BSON results or nil
  426. */
  427. FALCON_FUNC MongoDBConnection_find( VMachine* vm )
  428. {
  429. Item* i_ns = vm->param( 0 );
  430. Item* i_query = vm->param( 1 );
  431. Item* i_fields = vm->param( 2 );
  432. Item* i_skip = vm->param( 3 );
  433. Item* i_limit = vm->param( 4 );
  434. if ( !i_ns || !i_ns->isString()
  435. || ( i_query && !( i_query->isObject() && i_query->asObjectSafe()->derivedFrom( "BSON" ) ) )
  436. || ( i_fields && !( i_fields->isObject() && i_fields->asObjectSafe()->derivedFrom( "BSON" ) ) )
  437. || ( i_skip && !i_skip->isInteger() )
  438. || ( i_limit && !i_limit->isInteger() ) )
  439. {
  440. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  441. .extra( "S,[BSON,BSON,I,I]" ) );
  442. }
  443. CoreObject* self = vm->self().asObjectSafe();
  444. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  445. AutoCString zNs( *i_ns );
  446. MongoDB::BSONObj* query = i_query ?
  447. static_cast<MongoDB::BSONObj*>( i_query->asObjectSafe()->getUserData() ) : 0;
  448. MongoDB::BSONObj* fields = i_fields ?
  449. static_cast<MongoDB::BSONObj*>( i_fields->asObjectSafe()->getUserData() ) : 0;
  450. const int skip = i_skip ? i_skip->asInteger() : 0;
  451. const int limit = i_limit ? i_limit->asInteger() : 0;
  452. CoreArray* res;
  453. const bool b = conn->find( zNs.c_str(), query, fields, skip, limit, &res );
  454. if ( b )
  455. vm->retval( res );
  456. else
  457. vm->retnil();
  458. }
  459. /*#
  460. @method count MongoDB
  461. @brief Counts the entities in a collection.
  462. @param db Database
  463. @param coll Collection to be queried.
  464. @optparam query BSON instance
  465. @return Total count or -1 on error
  466. */
  467. FALCON_FUNC MongoDBConnection_count( VMachine* vm )
  468. {
  469. Item* i_db = vm->param( 0 );
  470. Item* i_coll = vm->param( 1 );
  471. Item* i_query = vm->param( 2 );
  472. if ( !i_db || !i_db->isString()
  473. || !i_coll || !i_coll->isString()
  474. || ( i_query && !( i_query->isObject() && i_query->asObjectSafe()->derivedFrom( "BSON" ) ) ) )
  475. {
  476. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  477. .extra( "S,S,[BSON]" ) );
  478. }
  479. CoreObject* self = vm->self().asObjectSafe();
  480. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  481. AutoCString db( *i_db );
  482. AutoCString coll( *i_coll );
  483. int64 n = -1;
  484. if ( i_query )
  485. {
  486. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( i_query->asObjectSafe()->getUserData() );
  487. n = conn->count( db.c_str(), coll.c_str(), bobj );
  488. }
  489. else
  490. n = conn->count( db.c_str(), coll.c_str() );
  491. vm->retval( n );
  492. }
  493. /*#
  494. @method command MongoDB
  495. @brief Run a command on a database
  496. @param db Database
  497. @param cmd BSON instance
  498. @return BSON result or nil
  499. */
  500. FALCON_FUNC MongoDBConnection_command( VMachine* vm )
  501. {
  502. Item* i_db = vm->param( 0 );
  503. Item* i_cmd = vm->param( 1 );
  504. if ( !i_db || !i_db->isString()
  505. || !i_cmd || !( i_cmd->isObject() && i_cmd->asObjectSafe()->derivedFrom( "BSON" ) ) )
  506. {
  507. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  508. .extra( "S,BSON" ) );
  509. }
  510. CoreObject* self = vm->self().asObjectSafe();
  511. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  512. AutoCString db( *i_db );
  513. MongoDB::BSONObj* cmd = static_cast<MongoDB::BSONObj*>( i_cmd->asObjectSafe()->getUserData() );
  514. MongoDB::BSONObj* res;
  515. if ( conn->command( db.c_str(), cmd, &res ) )
  516. {
  517. Item* wki = vm->findWKI( "BSON" );
  518. CoreObject* obj = wki->asClass()->createInstance();
  519. obj->setUserData( res );
  520. vm->retval( obj );
  521. }
  522. else
  523. vm->retnil();
  524. }
  525. /*#
  526. @method createIndex MongoDB
  527. @brief Creates an index for the given namespace and key.
  528. @param ns namespace
  529. @param key BSON instance
  530. @optparam unique (boolean) default false
  531. @optparam drop_dups (boolean) default false
  532. @return BSON result or nil
  533. */
  534. FALCON_FUNC MongoDBConnection_createIndex( VMachine* vm )
  535. {
  536. Item* i_ns = vm->param( 0 );
  537. Item* i_key = vm->param( 1 );
  538. Item* i_uniq = vm->param( 2 );
  539. Item* i_drups = vm->param( 3 );
  540. if ( !i_ns || !i_ns->isString()
  541. || !i_key || !( i_key->isObject() && i_key->asObjectSafe()->derivedFrom( "BSON" ) )
  542. || ( i_uniq && !i_uniq->isBoolean() )
  543. || ( i_drups && !i_drups->isBoolean() ) )
  544. {
  545. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  546. .extra( "S,BSON,[B,B]" ) );
  547. }
  548. CoreObject* self = vm->self().asObjectSafe();
  549. MongoDB::Connection* conn = static_cast<MongoDB::Connection*>( self->getUserData() );
  550. AutoCString zNs( *i_ns );
  551. MongoDB::BSONObj* key = static_cast<MongoDB::BSONObj*>( i_key->asObjectSafe()->getUserData() );
  552. const bool uniq = i_uniq ? i_uniq->asBoolean() : false;
  553. const bool drups = i_drups ? i_drups->asBoolean() : false;
  554. MongoDB::BSONObj* res;
  555. if ( conn->createIndex( zNs.c_str(), key, uniq, drups, &res ) )
  556. {
  557. CoreObject* obj = vm->findWKI( "BSON" )->asClass()->createInstance();
  558. obj->setUserData( res );
  559. vm->retval( obj );
  560. }
  561. else
  562. vm->retnil();
  563. }
  564. /*******************************************************************************
  565. ObjectID class
  566. *******************************************************************************/
  567. /*#
  568. @class ObjectID
  569. @brief Mongo Object ID
  570. @optparam string A string representing an object Id.
  571. */
  572. FALCON_FUNC MongoOID_init( VMachine* vm )
  573. {
  574. Item* i_s = vm->param( 0 );
  575. if ( i_s && !i_s->isString() )
  576. {
  577. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  578. .extra( "[S]" ) );
  579. }
  580. MongoDB::ObjectID* self = static_cast<MongoDB::ObjectID*>( vm->self().asObjectSafe() );
  581. if ( i_s )
  582. {
  583. AutoCString zStr( *i_s );
  584. self->fromString( zStr.c_str() );
  585. }
  586. vm->retval( self );
  587. }
  588. /*#
  589. @method toString ObjectID
  590. @brief Returns a representation of the object as a string.
  591. @return A string representing the object.
  592. */
  593. FALCON_FUNC MongoOID_toString( VMachine* vm )
  594. {
  595. MongoDB::ObjectID* self = static_cast<MongoDB::ObjectID*>( vm->self().asObjectSafe() );
  596. String s( self->toString() );
  597. s.bufferize();
  598. vm->retval( s );
  599. }
  600. /*******************************************************************************
  601. BSON class
  602. *******************************************************************************/
  603. /*#
  604. @class BSON
  605. @brief Represents a BSON object.
  606. @optparam param An integer (reserved space for internal buffer) or a dict to append.
  607. If no dict is given, an "empty" bson object is created.
  608. */
  609. FALCON_FUNC MongoBSON_init( VMachine* vm )
  610. {
  611. Item* i_parm = vm->param( 0 );
  612. if ( i_parm && !( i_parm->isInteger() || i_parm->isDict() ) )
  613. {
  614. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  615. .extra( "[I|D]" ) );
  616. }
  617. CoreObject* self = vm->self().asObjectSafe();
  618. const int bytes = i_parm && i_parm->isInteger() ? i_parm->asInteger() : 0;
  619. MongoDB::BSONObj* bobj = 0;
  620. bobj = new MongoDB::BSONObj( bytes );
  621. if ( !bobj )
  622. {
  623. throw new MongoDBError( ErrorParam( MONGODB_ERR_CREATE_BSON, __LINE__ )
  624. .desc( FAL_STR( _err_create_bsonobj ) ) );
  625. }
  626. if ( i_parm && i_parm->isDict() ) // append the data
  627. {
  628. const int ret = bobj->appendMany( *i_parm->asDict() );
  629. if ( ret == 1 ) // bad key
  630. {
  631. delete bobj;
  632. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  633. .extra( "S" ) );
  634. }
  635. else
  636. if ( ret == 2 ) // bad value
  637. {
  638. delete bobj;
  639. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  640. .extra( FAL_STR( _err_inv_item ) ) );
  641. }
  642. }
  643. self->setUserData( bobj );
  644. vm->retval( self );
  645. }
  646. /*#
  647. @method reset BSON
  648. @brief Clear the BSON object, making it an "empty" one.
  649. @optparam bytes Reserve some space for internal buffer.
  650. */
  651. FALCON_FUNC MongoBSON_reset( VMachine* vm )
  652. {
  653. Item* i_bytes = vm->param( 0 );
  654. if ( i_bytes && !i_bytes->isInteger() )
  655. {
  656. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  657. .extra( "[I]" ) );
  658. }
  659. const int bytes = i_bytes ? i_bytes->asInteger() : 0;
  660. CoreObject* self = vm->self().asObjectSafe();
  661. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  662. bobj->reset( bytes );
  663. }
  664. /*#
  665. @method genOID BSON
  666. @brief Generate and append an OID.
  667. @optparam name Key name (default "_id")
  668. @return self
  669. */
  670. FALCON_FUNC MongoBSON_genOID( VMachine* vm )
  671. {
  672. Item* i_nm = vm->param( 0 );
  673. if ( i_nm && !i_nm->isString() )
  674. {
  675. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  676. .extra( "[S]" ) );
  677. }
  678. CoreObject* self = vm->self().asObjectSafe();
  679. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  680. if ( i_nm )
  681. {
  682. AutoCString zNm( *i_nm );
  683. bobj->genOID( zNm.c_str() );
  684. }
  685. else
  686. bobj->genOID( "_id" );
  687. vm->retval( self );
  688. }
  689. /*#
  690. @method append BSON
  691. @brief Append some data to the BSON object
  692. @param dict A dict (with keys that must be strings...)
  693. @return self
  694. Example:
  695. @code
  696. import from mongo
  697. obj = mongo.BSON().genOID().append( [ "key" => "value" ] )
  698. @endcode
  699. */
  700. FALCON_FUNC MongoBSON_append( VMachine* vm )
  701. {
  702. Item* i_dic = vm->param( 0 );
  703. if ( !i_dic || !i_dic->isDict() )
  704. {
  705. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  706. .extra( "D" ) );
  707. }
  708. CoreDict* dic = i_dic->asDict();
  709. CoreObject* self = vm->self().asObjectSafe();
  710. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  711. const int ret = bobj->appendMany( *dic );
  712. if ( ret == 1 ) // bad key
  713. {
  714. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  715. .extra( "S" ) );
  716. }
  717. else
  718. if ( ret == 2 ) // bad value
  719. {
  720. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  721. .extra( FAL_STR( _err_inv_item ) ) );
  722. }
  723. vm->retval( self );
  724. }
  725. /*#
  726. @method asDict BSON
  727. @brief Return a dictionary representing the BSON object.
  728. @return A dictionary
  729. */
  730. FALCON_FUNC MongoBSON_asDict( VMachine* vm )
  731. {
  732. CoreObject* self = vm->self().asObjectSafe();
  733. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  734. vm->retval( bobj->asDict() );
  735. }
  736. /*#
  737. @method hasKey BSON
  738. @brief Checks if the collection contains the required key.
  739. @param key
  740. @return true if BSON has that key
  741. */
  742. FALCON_FUNC MongoBSON_hasKey( VMachine* vm )
  743. {
  744. Item* i_key = vm->param( 0 );
  745. if ( !i_key || !i_key->isString() )
  746. {
  747. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  748. .extra( "S" ) );
  749. }
  750. CoreObject* self = vm->self().asObjectSafe();
  751. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  752. AutoCString key( *i_key );
  753. vm->retval( bobj->hasKey( key.c_str() ) );
  754. }
  755. /*#
  756. @method value BSON
  757. @brief Changes the value for a given key, or inserts a new key.
  758. @param key The key of which the value should be changed or inserted.
  759. @return value for key given (might be nil), or nil.
  760. */
  761. FALCON_FUNC MongoBSON_value( VMachine* vm )
  762. {
  763. Item* i_key = vm->param( 0 );
  764. if ( !i_key || !i_key->isString() )
  765. {
  766. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  767. .extra( "S" ) );
  768. }
  769. CoreObject* self = vm->self().asObjectSafe();
  770. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( self->getUserData() );
  771. AutoCString key( *i_key );
  772. Item* it = bobj->value( key.c_str() );
  773. if ( it )
  774. vm->retval( *it );
  775. else
  776. vm->retnil();
  777. }
  778. /*******************************************************************************
  779. BSONIter class
  780. *******************************************************************************/
  781. /*#
  782. @class BSONIter
  783. @brief Iterator for BSON objects
  784. @param bson A BSON object
  785. Example:
  786. @code
  787. iter = BSONIter( bson )
  788. while iter.next()
  789. doSomething( iter.key(), iter.value() )
  790. end
  791. @endcode
  792. The iterator copies data from given BSON object, and is completely
  793. independant and cannot be changed or updated. (This is of course suboptimal
  794. and could be optimized later.)
  795. */
  796. FALCON_FUNC MongoBSONIter_init( VMachine* vm )
  797. {
  798. Item* i_data = vm->param( 0 );
  799. if ( !i_data
  800. || !( i_data->isObject() && i_data->asObjectSafe()->derivedFrom( "BSON" ) ) )
  801. {
  802. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  803. .extra( "BSON" ) );
  804. }
  805. CoreObject* self = vm->self().asObjectSafe();
  806. CoreObject* data = i_data->asObjectSafe();
  807. MongoDB::BSONObj* bobj = static_cast<MongoDB::BSONObj*>( data->getUserData() );
  808. MongoDB::BSONIter* iter = new MongoDB::BSONIter( bobj );
  809. self->setUserData( iter );
  810. vm->retval( self );
  811. }
  812. /*#
  813. @method next BSONIter
  814. @brief Return true if there is more data to iterate over
  815. @return True if the iterator could advance, false if it was the last element.
  816. */
  817. FALCON_FUNC MongoBSONIter_next( VMachine* vm )
  818. {
  819. CoreObject* self = vm->self().asObjectSafe();
  820. MongoDB::BSONIter* iter = static_cast<MongoDB::BSONIter*>( self->getUserData() );
  821. vm->retval( iter->next() );
  822. }
  823. /*#
  824. @method key BSONIter
  825. @brief Get the current BSON key string
  826. @return The current key.
  827. */
  828. FALCON_FUNC MongoBSONIter_key( VMachine* vm )
  829. {
  830. CoreObject* self = vm->self().asObjectSafe();
  831. MongoDB::BSONIter* iter = static_cast<MongoDB::BSONIter*>( self->getUserData() );
  832. const char* k = iter->currentKey();
  833. if ( k )
  834. {
  835. String s( k );
  836. s.bufferize();
  837. vm->retval( s );
  838. }
  839. else
  840. vm->retnil();
  841. }
  842. /*#
  843. @method value BSONIter
  844. @brief Get the current BSON value
  845. @return The current value.
  846. */
  847. FALCON_FUNC MongoBSONIter_value( VMachine* vm )
  848. {
  849. CoreObject* self = vm->self().asObjectSafe();
  850. MongoDB::BSONIter* iter = static_cast<MongoDB::BSONIter*>( self->getUserData() );
  851. Item* v = iter->currentValue();
  852. if ( v )
  853. vm->retval( *v );
  854. else
  855. vm->retnil();
  856. }
  857. /*#
  858. @method reset BSONIter
  859. @brief Reset to start of iterator.
  860. */
  861. FALCON_FUNC MongoBSONIter_reset( VMachine* vm )
  862. {
  863. CoreObject* self = vm->self().asObjectSafe();
  864. MongoDB::BSONIter* iter = static_cast<MongoDB::BSONIter*>( self->getUserData() );
  865. iter->reset();
  866. }
  867. /*#
  868. @method find BSONIter
  869. @param name Key name
  870. @brief Return true when (and set iterator position where) name is found in the BSON.
  871. @return True if the key can be found, false otherwise.
  872. If false is returned, iterator is at end (and you may have to reset it).
  873. This method does a reset before searching.
  874. */
  875. FALCON_FUNC MongoBSONIter_find( VMachine* vm )
  876. {
  877. Item* i_nm = vm->param( 0 );
  878. if ( !i_nm || !i_nm->isString() )
  879. {
  880. throw new ParamError( ErrorParam( e_inv_params, __LINE__ )
  881. .extra( "S" ) );
  882. }
  883. CoreObject* self = vm->self().asObjectSafe();
  884. MongoDB::BSONIter* iter = static_cast<MongoDB::BSONIter*>( self->getUserData() );
  885. AutoCString zNm( *i_nm->asString() );
  886. vm->retval( iter->find( zNm.c_str() ) );
  887. }
  888. } /* !namespace Ext */
  889. } /* !namespace Falcon */