1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
19 # This is actually a wrapper around the [MongoDB C Driver](http://api.mongodb.org/c/1.1.4/index.html).
24 # # Opens the connexion with the Mongo server.
25 # var client = new MongoClient("mongodb://localhost:27017/")
27 # # Retrieve a collection.
28 # var col = client.database("test").collection("test")
30 # # Insert a document in the collection.
31 # var doc = new JsonObject
34 # doc["baz"] = new JsonArray
35 # assert col.insert(doc)
37 # # Retrieve a document from the collection.
38 # var query = new JsonObject
40 # var res = col.find(query)
41 # assert res["bar"] == "bar"
44 # TODO Get last Object_ID
48 private import native_mongodb
54 # Everything inside MongoDB is manipulated as BSON Objects.
57 # * [Binary JSON spec](http://bsonspec.org/)
58 # * [Libbson](http://api.mongodb.org/libbson/1.1.4/)#
62 # Native instance pointer.
63 var native
: NativeBSON
65 # Is the native instance valid?
67 # This is set to false if the `native` is destroyed.
70 # Returns a new BSON object initialized from the content of `json`.
73 # intrude import mongodb
74 # var obj = new JsonObject
76 # obj["name"] = "Rick"
77 # obj["ELS"] = new JsonArray
78 # var bson = new BSON.from_json(obj)
79 # assert bson.to_s == """{ "age" : 10, "name" : "Rick", "ELS" : [ ] }"""
81 init from_json
(json
: JsonObject) do
82 init(new NativeBSON.from_json_string
(json
.to_json
.to_cstring
))
85 # Returns a new BSON object parsed from `json_string`.
87 # If `json_string` is not a valid JSON string, this initializer returns NULL.
90 # intrude import mongodb
91 # var str = """{ "age" : 10, "name" : "Rick", "ELS" : [ ] }"""
92 # var bson = new BSON.from_json_string(str)
93 # assert bson.to_s == str
95 init from_json_string
(json_string
: String) do
96 init(new NativeBSON.from_json_string
(json_string
.to_cstring
))
101 var ns
= native
.to_native_string
102 var res
= ns
.to_s_with_copy
103 ns
.free
# manual free of gc allocated NativeString
107 # Returns a new JsonObject from `self`.
110 # intrude import mongodb
111 # var str = """{ "age" : 10, "name" : "Rick", "ELS" : [ ] }"""
112 # var bson = new BSON.from_json_string(str)
113 # var json = bson.to_json
114 # assert json["age"] == 10
115 # assert json["name"] == "Rick"
116 # assert json["ELS"].as(JsonArray).is_empty
118 fun to_json
: JsonObject do
120 return to_s
.parse_json
.as(JsonObject)
123 redef fun finalize
do
131 redef class JsonObject
132 # Inits `self` from a BSON object.
133 private init from_bson
(bson
: BSON) do recover_with
(bson
.to_json
)
135 # Returns a new BSON object from `self`.
136 private fun to_bson
: BSON do return new BSON.from_json
(self)
139 # An error returned by the mongoc client.
141 # Within the client, if a method returns `false` or `null` it's more likely that
142 # an error occured during the execution.
144 # See `MongoClient::last_error`.
147 private var native
: BSONError
149 # Is the native instance valid?
151 # This is set to false if the `native` is destroyed.
152 private var is_alive
= true
154 # Logical domain within a library that created the error.
160 # Domain specific error code.
166 # Human readable error message.
167 fun message
: String do
169 var ns
= native
.message
170 var res
= ns
.to_s_with_copy
175 redef fun to_s
do return "{message} (code: {code})"
178 # The MongoClient is used to connect to the mongo server and send queries.
183 # var uri = "mongodb://localhost:27017/"
184 # var client = new MongoClient(uri)
185 # assert client.server_uri == uri
191 var server_uri
: String
193 private var native
: NativeMongoClient is noinit
195 # Is the native instance valid?
197 # This is set to false if the `native` is destroyed.
198 private var is_alive
= true
201 native
= new NativeMongoClient(server_uri
.to_cstring
)
206 # Returns `null` if an error occured. See `last_error`.
209 # var client = new MongoClient("mongodb://localhost:27017/")
210 # assert client.server_status["process"] == "mongod"
212 fun server_status
: nullable JsonObject do
214 var nbson
= native
.server_status
215 if nbson
== null then return null
216 var bson
= new BSON(nbson
)
217 var res
= new JsonObject.from_bson
(bson
)
221 # Lists available database names.
224 # var client = new MongoClient("mongodb://localhost:27017/")
225 # var db = client.database("test")
226 # db.collection("test").insert(new JsonObject)
227 # assert client.database_names.has("test")
229 fun database_names
: Array[String] do
231 var res
= new Array[String]
232 var nas
= native
.database_names
235 while not name
.address_is_null
do
236 res
.add name
.to_s_with_copy
244 # Loads or creates a database from its `name`.
246 # Database are automatically created on the MongoDB server upon insertion of
247 # the first document into a collection.
248 # There is no need to create a database manually.
251 # var client = new MongoClient("mongodb://localhost:27017/")
252 # assert client.database("test").name == "test"
254 fun database
(name
: String): MongoDb do
256 return new MongoDb(self, name
)
259 # Close the connexion and destroy the instance.
261 # The reference should not be used beyond this point!
267 redef fun finalize
do
274 # Last error raised by mongoc.
275 fun last_error
: nullable MongoError do
276 var last_error
= sys
.last_mongoc_error
277 if last_error
== null then return null
278 return new MongoError(last_error
)
282 # A MongoDb database.
284 # Database are automatically created on the MongoDB server upon insertion of the
285 # first document into a collection.
286 # There is no need to create a database manually.
290 # `MongoClient` used to load this database.
291 var client
: MongoClient
296 private var native
: NativeMongoDb is noinit
298 # Is the native instance valid?
300 # This is set to false if the `native` is destroyed.
301 private var is_alive
= true
304 native
= new NativeMongoDb(client
.native
, name
.to_cstring
)
307 # Lists available collection names.
309 # Returns `null` if an error occured. See `Sys::last_mongoc_error`.
312 # var client = new MongoClient("mongodb://localhost:27017/")
313 # var db = client.database("test")
314 # db.collection("test").insert(new JsonObject)
315 # assert db.collection_names.has("test")
317 fun collection_names
: Array[String] do
319 var res
= new Array[String]
320 var nas
= native
.collection_names
323 while not name
.address_is_null
do
324 res
.add name
.to_s_with_copy
332 # Loads or creates a collection by its `name`.
335 # var client = new MongoClient("mongodb://localhost:27017/")
336 # var db = client.database("test")
337 # var col = db.collection("test")
338 # assert col.name == "test"
340 fun collection
(name
: String): MongoCollection do
342 return new MongoCollection(self, name
)
345 # Checks if a collection named `name` exists.
348 # var client = new MongoClient("mongodb://localhost:27017/")
349 # var db = client.database("test")
350 # assert not db.has_collection("qwerty")
352 fun has_collection
(name
: String): Bool do
355 return native
.has_collection
(name
.to_cstring
)
358 # Drop `self`, returns false if an error occured.
364 redef fun finalize
do
372 # A Mongo collection.
374 # Collections are automatically created on the MongoDB server upon insertion of
375 # the first document.
376 # There is no need to create a database manually.
377 class MongoCollection
380 # Database that collection belongs to.
381 var database
: MongoDb
383 # Name of this collection.
386 private var native
: NativeMongoCollection is noinit
388 # Is the native instance valid?
390 # This is set to false if the `native` is destroyed.
391 private var is_alive
= true
393 # Loads a collection.
395 # Call `MongoDb::collection` instead.
397 native
= new NativeMongoCollection(
398 database
.client
.native
,
399 database
.name
.to_cstring
,
403 # Inserts a new document in the collection.
405 # If no _id element is found in document, then a new one be generated locally
406 # and added to the document.
408 # Returns `false` if an error occured. See `Sys::last_mongoc_error`.
411 # var client = new MongoClient("mongodb://localhost:27017/")
412 # var col = client.database("test").collection("test")
413 # var doc = new JsonObject
416 # doc["baz"] = new JsonArray
417 # assert col.insert(doc)
419 fun insert
(doc
: JsonObject): Bool do
421 return native
.insert
(doc
.to_bson
.native
)
424 # Inserts multiple documents in the collection.
427 fun insert_all
(docs
: Collection[JsonObject]): Bool do
430 for doc
in docs
do res
= insert
(doc
) and res
434 # Saves a new document in the collection.
436 # If the document has an `_id` field it will be updated.
437 # Otherwise it will be inserted.
439 # Returns `false` if an error occured. See `Sys::last_mongoc_error`.
442 # var client = new MongoClient("mongodb://localhost:27017/")
443 # var col = client.database("test").collection("test")
444 # var doc = new JsonObject
447 # doc["baz"] = new JsonArray
448 # assert col.save(doc) # will be inserted
450 fun save
(doc
: JsonObject): Bool do
452 return native
.save
(doc
.to_bson
.native
)
455 # Removes the first document that matches `selector`.
457 # Returns `false` if an error occured. See `Sys::last_mongoc_error`.
460 # var client = new MongoClient("mongodb://localhost:27017/")
461 # var col = client.database("test").collection("test")
462 # var sel = new JsonObject
464 # assert col.remove(sel)
466 fun remove
(selector
: JsonObject): Bool do
468 return native
.remove
(selector
.to_bson
.native
)
471 # Removes all the document that match `selector`.
474 fun remove_all
(selector
: JsonObject): Bool do
476 return native
.remove_all
(selector
.to_bson
.native
)
479 # Updates a document already existing in the collection.
481 # No upsert is done, see `save` instead.
484 # var client = new MongoClient("mongodb://localhost:27017/")
485 # var col = client.database("test").collection("test")
486 # var sel = new JsonObject
488 # var upd = new JsonObject
490 # assert col.update(sel, upd)
492 fun update
(selector
: JsonObject, update
: JsonObject): Bool do
494 return native
.update
(
495 selector
.to_bson
.native
,
496 update
.to_bson
.native
)
499 # Updates all documents matching the `selector`.
502 fun update_all
(selector
: JsonObject, update
: JsonObject): Bool do
503 return native
.update_all
(
504 selector
.to_bson
.native
,
505 update
.to_bson
.native
)
508 # Counts the document matching `query`.
510 # Returns `-1` if an error occured. See `Sys::last_mongoc_error`.
513 # var client = new MongoClient("mongodb://localhost:27017/")
514 # var col = client.database("test").collection("test")
515 # var query = new JsonObject
517 # assert col.count(query) > 0
519 fun count
(query
: JsonObject): Int do
521 return native
.count
(query
.to_bson
.native
)
524 # Finds the first document that matches `query`.
526 # Returns `null` if an error occured. See `Sys::last_mongoc_error`.
529 # var client = new MongoClient("mongodb://localhost:27017/")
530 # var col = client.database("test").collection("test")
531 # var query = new JsonObject
533 # var doc = col.find(query)
534 # print doc or else "nullllllllllllllllll"
536 # assert doc["foo"] == 10
538 fun find
(query
: JsonObject): nullable JsonObject do
540 var c
= native
.find
(query
.to_bson
.native
)
541 if c
== null then return null
542 var cursor
= new MongoCursor(c
)
550 # Finds all the documents matching the `query`.
553 # var client = new MongoClient("mongodb://localhost:27017/")
554 # var col = client.database("test").collection("test")
555 # var query = new JsonObject
557 # assert col.find_all(query).length > 0
559 fun find_all
(query
: JsonObject): Array[JsonObject] do
561 var res
= new Array[JsonObject]
562 var c
= native
.find
(query
.to_bson
.native
)
563 if c
== null then return res
564 var cursor
= new MongoCursor(c
)
565 for item
in cursor
do res
.add item
569 # Retrieves statistics about the collection.
571 # Returns `null` if an error occured. See `Sys::last_mongoc_error`.
574 # var client = new MongoClient("mongodb://localhost:27017/")
575 # var col = client.database("test").collection("test")
576 # assert col.stats["ns"] == "test.test"
578 fun stats
: nullable JsonObject do
580 var bson
= native
.stats
581 if bson
== null then return null
582 return new JsonObject.from_bson
(new BSON(bson
))
585 # Drops `self`, returns false if an error occured.
591 # Moves `self` to another `database`.
593 # The database will also be updated internally so it is safe to continue using
594 # this collection after the move.
595 # Additional operations will occur on moved collection.
596 fun move
(database
: MongoDb): Bool do
598 self.database
= database
599 return native
.rename
(database
.name
.to_cstring
, name
.to_cstring
)
604 # The name of the collection will also be updated internally so it is safe
605 # to continue using this collection after the rename.
606 # Additional operations will occur on renamed collection.
607 fun rename
(name
: String): Bool do
610 return native
.rename
(database
.name
.to_cstring
, name
.to_cstring
)
613 redef fun finalize
do
621 # A MongoDB query cursor.
623 # It wraps up the wire protocol negotation required to initiate a query and
624 # retreive an unknown number of documents.
627 super Iterator[JsonObject]
629 private var native
: NativeMongoCursor
631 # Is the native instance valid?
633 # This is set to false if the `native` is destroyed.
634 private var is_alive
= true
650 return new JsonObject.from_bson
(new BSON(native
.current
))
653 redef fun finalize
do