*: update all clients of the `CString::to_s` services
[nit.git] / lib / mongodb / native_mongodb.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2015 Alexandre Terrasa <alexandre@moz-code.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # Native wrapper for the MongoDB C Driver
18 #
19 # See [mongoc](http://api.mongodb.org/c/1.1.4/index.html).
20 module native_mongodb is pkgconfig "libmongoc-1.0"
21
22 import c
23
24 in "C header" `{
25 #include <mongoc.h>
26 `}
27
28 # Wrapper for `bson_t`.
29 #
30 # All data manipulated by `mongoc` are BSON formated.
31 #
32 # The `bson_t` structure represents a BSON document.
33 # This structure manages the underlying BSON encoded buffer.
34 # For mutable documents, it can append new data to the document.
35 #
36 # See [`bson_t`](http://api.mongodb.org/libbson/current/bson_t.html).
37 extern class NativeBSON `{ bson_t * `}
38
39 # Wrapper for `bson_new()`.
40 #
41 # The `bson_new()` function shall create a new `bson_t` structure on the heap.
42 # It should be freed with `bson_destroy()` when it is no longer in use.
43 new `{ return bson_new(); `}
44
45 # Wrapper for `bson_new_from_json()`.
46 #
47 # The `bson_new_from_json()` function allocates and initialize a new `bson_t`
48 # by parsing the JSON found in `data`.
49 # Only a single JSON object may exist in data or an error will be set and
50 # `NULL` returned.
51 new from_json_string(data: CString) import set_mongoc_error `{
52 bson_error_t error;
53 bson_t *bson;
54 bson = bson_new_from_json((uint8_t *)data, -1, &error);
55 if(!bson) {
56 NativeBSON_set_mongoc_error(bson, &error);
57 return NULL;
58 }
59 return bson;
60 `}
61
62 # Wrapper for `bson_as_json()`.
63 #
64 # The `bson_as_json()` function shall encode bson as a JSON encoded UTF-8 string.
65 # The caller is responsible for freeing the resulting UTF-8 encoded string
66 # by calling `bson_free()` with the result.
67 fun to_c_string: CString `{ return bson_as_json(self, NULL); `}
68
69 # Wrapper for `bson_destroy()`.
70 #
71 # The `bson_destroy()` function shall free an allocated `bson_t` structure.
72 # This function should always be called when you are done with a `bson_t`
73 # unless otherwise specified.
74 #
75 # This instance should not be used beyond this point!
76 fun destroy `{ bson_destroy(self); `}
77
78 # Utility method to set `Sys.last_mongoc_error`.
79 fun set_mongoc_error(err: BSONError) do sys.last_mongoc_error = err
80 end
81
82 # Wrapper for `bson_error_t`.
83 #
84 # The `bson_error_t` structure is used to encapsulate information about an error.
85 #
86 # See [`bson_error_t`](http://api.mongodb.org/libbson/current/bson_error_t.html).
87 extern class BSONError `{ bson_error_t * `}
88
89 # Wrapper for `error.domain`.
90 #
91 # The `error.domain` field contains the logical domain within a library that
92 # created the error.
93 fun domain: Int `{ return self->domain; `}
94
95 # Wrapper for `error.code`.
96 #
97 # The `error.code` field contains the domain specific error code.
98 fun code: Int `{ return self->code; `}
99
100 # Wrapper for `error.message`.
101 #
102 # The `error.message` field contains a human printable error message.
103 fun message: CString `{ return self->message; `}
104 end
105
106 # Wrapper for `bson_oid_t`.
107 #
108 # The `bson_oid_t` structure contains the 12-byte ObjectId notation defined by the
109 # [BSON ObjectID specificiation](http://docs.mongodb.org/manual/reference/object-id/).
110 #
111 # ObjectId is a 12-byte BSON type, constructed using:
112 # * a 4-byte value representing the seconds since the Unix epoch (in Big Endian)
113 # * a 3-byte machine identifier
114 # * a 2-byte process id (Big Endian), and
115 # * a 3-byte counter (Big Endian), starting with a random value.
116 extern class BSONObjectId `{ bson_oid_t * `}
117
118 # Generates a new `bson_oid_t`.
119 new `{
120 bson_oid_t *self = malloc(sizeof(bson_oid_t));
121 bson_oid_init(self, NULL);
122 return self;
123 `}
124
125 # Object id.
126 fun id: String import CString.to_s `{
127 char str[25];
128 bson_oid_to_string(self, str);
129 return CString_to_s(str);
130 `}
131
132 # Destroy `self`.
133 fun destroy `{ free(self); `}
134 end
135
136 redef class Sys
137 # Last error raised by `monogdb::MongoClient`.
138 #
139 # See `MongoClient::last_error`.
140 var last_mongoc_error: nullable BSONError = null
141
142 # Last auto generated id if any.
143 #
144 # See `MongoCollection::insert`.
145 var last_mongoc_id: nullable BSONObjectId = null is writable
146 end
147
148 # Wrapper for `char**`.
149 #
150 # Used to handle array of CString returned by MongoDB.
151 redef class NativeCStringArray
152 # Frees `self`.
153 #
154 # This instance should not be used beyond this point!
155 fun destroy `{ free(self); `}
156 end
157
158 # Wrapper for `mongoc_client_t`.
159 #
160 # `mongoc_client_t` is an opaque type that provides access to a MongoDB node,
161 # replica-set, or sharded-cluster.
162 # It maintains management of underlying sockets and routing to individual nodes.
163 #
164 # See [`mongoc_client_t`](http://api.mongodb.org/c/current/mongoc_client_t.html).
165 extern class NativeMongoClient `{ mongoc_client_t * `}
166
167 # Wrapper for `mongoc_client_new()`.
168 #
169 # Creates a new `mongoc_client_t` using the `uri` string provided.
170 new(uri: CString) `{
171 mongoc_init();
172 return mongoc_client_new(uri);
173 `}
174
175 # Wrapper for `mongoc_client_get_server_status()`.
176 #
177 # Queries the server for the current server status.
178 # Returns `null` if an error occured.
179 fun server_status: nullable NativeBSON import set_mongoc_error, NativeBSON.as nullable `{
180 bson_error_t error;
181 bson_t *reply = bson_new();
182 if(!mongoc_client_get_server_status(self, NULL, reply, &error)){
183 NativeMongoClient_set_mongoc_error(self, &error);
184 return null_NativeBSON();
185 }
186 return NativeBSON_as_nullable(reply);
187 `}
188
189 # Wrapper for `mongoc_client_get_database_names()`.
190 #
191 # This function queries the MongoDB server for a list of known databases.
192 # Returns `null` if an error occured.
193 fun database_names: nullable NativeCStringArray
194 import set_mongoc_error, NativeCStringArray, NativeCStringArray.as nullable `{
195 bson_error_t error;
196 char **strv;
197 if((strv = mongoc_client_get_database_names(self, &error))) {
198 return NativeCStringArray_as_nullable(strv);
199 }
200 NativeMongoClient_set_mongoc_error(self, &error);
201 return null_NativeCStringArray();
202 `}
203
204 # Wrapper for `mongoc_client_destroy()`.
205 #
206 # This instance should not be used beyond this point!
207 fun destroy `{
208 mongoc_client_destroy(self);
209 mongoc_cleanup();
210 `}
211
212 # Utility method to set `Sys.last_mongoc_error`.
213 fun set_mongoc_error(err: BSONError) do sys.last_mongoc_error = err
214 end
215
216 # Wrapper for `mongoc_database_t`.
217 #
218 # `mongoc_database_t` provides access to a MongoDB database.
219 # This handle is useful for actions a particular database object.
220 # It is not a container for `mongoc_collection_t` structures.
221 #
222 # See [`mongoc_database_t`](http://api.mongodb.org/c/current/mongoc_database_t.html).
223 extern class NativeMongoDb `{ mongoc_database_t * `}
224
225 # Wrapper for `mongoc_client_get_database()`.
226 #
227 # Get a newly allocated `mongoc_database_t` for the database named name.
228 #
229 # Database are automatically created on the MongoDB server upon insertion of
230 # the first document into a collection.
231 # There is no need to create a database manually.
232 new(client: NativeMongoClient, db_name: CString) `{
233 return mongoc_client_get_database(client, db_name);
234 `}
235
236 # Wrapper for `mongoc_database_get_collection_names()`.
237 #
238 # Fetches a `NULL` terminated array of `NULL-byte` terminated `char*` strings
239 # containing the names of all of the collections in database.
240 fun collection_names: nullable NativeCStringArray
241 import set_mongoc_error, NativeCStringArray, NativeCStringArray.as nullable `{
242 bson_error_t error;
243 char **strv;
244 if((strv = mongoc_database_get_collection_names(self, &error))) {
245 return NativeCStringArray_as_nullable(strv);
246 }
247 NativeMongoDb_set_mongoc_error(self, &error);
248 return null_NativeCStringArray();
249 `}
250
251 # Wrapper for `mongoc_database_get_collection()`.
252 #
253 # Allocates a new `mongoc_collection_t` structure for the collection named
254 # `name` in database.
255 fun collection(name: CString): NativeMongoCollection `{
256 return mongoc_database_get_collection(self, name);
257 `}
258
259 # Wrapper for `mongoc_database_has_collection()`.
260 #
261 # This function checks to see if a collection exists on the MongoDB server
262 # within database.
263 fun has_collection(name: CString): Bool import set_mongoc_error `{
264 bson_error_t error;
265 if(!mongoc_database_has_collection(self, name, &error)) {
266 NativeMongoDb_set_mongoc_error(self, &error);
267 return false;
268 }
269 return true;
270 `}
271
272 # Wrapper for `mongoc_database_drop()`.
273 #
274 # This function attempts to drop a database on the MongoDB server.
275 fun drop: Bool import set_mongoc_error `{
276 bson_error_t error;
277 if(!mongoc_database_drop(self, &error)) {
278 NativeMongoDb_set_mongoc_error(self, &error);
279 return false;
280 }
281 return true;
282 `}
283
284 # Wrapper for `mongoc_database_destroy()`.
285 #
286 # This instance should not be used beyond this point!
287 fun destroy `{ mongoc_database_destroy(self); `}
288
289 # Utility method to set `Sys.last_mongoc_error`.
290 fun set_mongoc_error(err: BSONError) do sys.last_mongoc_error = err
291 end
292
293 # Wrapper for `mongoc_collection_t`.
294 #
295 # `mongoc_collection_t` provides access to a MongoDB collection.
296 # This handle is useful for actions for most CRUD operations,
297 # I.e. insert, update, delete, find, etc.
298 #
299 # It is an error to call `mongoc_collection_destroy()` on a collection that has
300 # operations pending.
301 # It is required that you release `mongoc_cursor_t` structures before calling
302 # `mongoc_collection_destroy()`.
303 #
304 # See [`mongoc_collection_t`](http://api.mongodb.org/c/current/mongoc_collection_t.html).
305 extern class NativeMongoCollection `{ mongoc_collection_t * `}
306
307 # Wrapper for `mongoc_client_get_collection()`.
308 #
309 # Get a newly allocated `mongoc_collection_t` for the collection named
310 # `collection` in the database named `db`.
311 #
312 # Collections are automatically created on the MongoDB server upon insertion
313 # of the first document.
314 # There is no need to create a collection manually.
315 new(client: NativeMongoClient, db, collection: CString) `{
316 return mongoc_client_get_collection(client, db, collection);
317 `}
318
319 # Wrapper for `mongoc_collection_insert()`.
320 #
321 # This function shall insert `document` into the collection.
322 # If no `_id` element is found in document, then a `bson_oid_t` will be
323 # generated locally and added to the document.
324 #
325 # You can retrieve a generated `_id` from `sys.last_mongoc_id`.
326 fun insert(document: NativeBSON): Bool import set_mongoc_error, set_mongoc_last_id `{
327 bson_oid_t oid;
328 if(!bson_has_field(document, "_id")) {
329 bson_oid_init (&oid, NULL);
330 BSON_APPEND_OID (document, "_id", &oid);
331 NativeMongoCollection_set_mongoc_last_id(self, &oid);
332 }
333 bson_error_t error;
334 if(!mongoc_collection_insert(self, MONGOC_INSERT_NONE, document, NULL, &error)) {
335 NativeMongoCollection_set_mongoc_error(self, &error);
336 return false;
337 }
338 return true;
339 `}
340
341 # Wrapper for `mongoc_collection_save()`.
342 #
343 # This function shall save a document into the collection.
344 # If the document has an `_id` field it will be updated.
345 # Otherwise it will be inserted.
346 #
347 # You can retrieve a generated `_id` from `sys.last_mongoc_id`.
348 fun save(document: NativeBSON): Bool import set_mongoc_error, set_mongoc_last_id `{
349 bson_oid_t oid;
350 if(!bson_has_field(document, "_id")) {
351 bson_oid_init (&oid, NULL);
352 BSON_APPEND_OID (document, "_id", &oid);
353 NativeMongoCollection_set_mongoc_last_id(self, &oid);
354 }
355 bson_error_t error;
356 if(!mongoc_collection_save(self, document, NULL, &error)) {
357 NativeMongoCollection_set_mongoc_error(self, &error);
358 return false;
359 }
360 return true;
361 `}
362
363 # Wrapper for `mongoc_collection_remove(MONGOC_REMOVE_SINGLE_REMOVE)`.
364 #
365 # This function shall remove the first document in the collection that matches
366 # `selector`.
367 # The bson selector is not validated, simply passed along as appropriate to the server.
368 fun remove(selector: NativeBSON): Bool import set_mongoc_error `{
369 bson_error_t error;
370 if(!mongoc_collection_remove(self, MONGOC_REMOVE_SINGLE_REMOVE, selector, NULL, &error)) {
371 NativeMongoCollection_set_mongoc_error(self, &error);
372 return false;
373 }
374 return true;
375 `}
376
377 # Wrapper for `mongoc_collection_remove(MONGOC_REMOVE_NONE)`.
378 #
379 # This function shall remove documents in the collection that match `selector`.
380 fun remove_all(selector: NativeBSON): Bool import set_mongoc_error `{
381 bson_error_t error;
382 if(!mongoc_collection_remove(self, MONGOC_REMOVE_NONE, selector, NULL, &error)) {
383 NativeMongoCollection_set_mongoc_error(self, &error);
384 return false;
385 }
386 return true;
387 `}
388
389 # Wrapper for `mongoc_collection_update(MONGOC_UPDATE_NONE)`.
390 #
391 # This function shall update the first document in the collection that
392 # matches `selector`.
393 fun update(selector, update: NativeBSON): Bool import set_mongoc_error `{
394 bson_error_t error;
395 if(!mongoc_collection_update(self, MONGOC_UPDATE_NONE, selector, update, NULL, &error)) {
396 NativeMongoCollection_set_mongoc_error(self, &error);
397 return false;
398 }
399 return true;
400 `}
401
402 # Wrapper for `mongoc_collection_update(MONGOC_UPDATE_MULTI_UPDATE)`.
403 #
404 # This function shall update documents in the collection that match `selector`.
405 fun update_all(selector, update: NativeBSON): Bool import set_mongoc_error `{
406 bson_error_t error;
407 if(!mongoc_collection_update(self, MONGOC_UPDATE_MULTI_UPDATE, selector, update, NULL, &error)) {
408 NativeMongoCollection_set_mongoc_error(self, &error);
409 return false;
410 }
411 return true;
412 `}
413
414 # Wrapper for `mongoc_collection_count()`.
415 #
416 # This function shall execute a count `query` on the underlying collection.
417 fun count(query: NativeBSON): Int import set_mongoc_error `{
418 bson_error_t error;
419 int64_t count = mongoc_collection_count(self, MONGOC_QUERY_NONE, query, 0, 0, NULL, &error);
420 if(count < 0) {
421 NativeMongoCollection_set_mongoc_error(self, &error);
422 return -1;
423 }
424 return count;
425 `}
426
427 # Wrapper for `mongoc_collection_find()`.
428 #
429 # This function shall execute a `query` on the underlying collection.
430 #
431 # If no options are necessary, `query` can simply contain a query such as `{a:1}`.
432 #
433 # If you would like to specify options such as a sort order,
434 # the query must be placed inside of `{"$query": {}}`.
435 fun find(query: NativeBSON, skip, limit: Int): nullable NativeMongoCursor import
436 NativeMongoCursor.as nullable, set_mongoc_error `{
437 bson_error_t error;
438 mongoc_cursor_t *cursor;
439 cursor = mongoc_collection_find(self, MONGOC_QUERY_NONE, skip, limit, 0, query, NULL, NULL);
440 if (mongoc_cursor_error(cursor, &error)) {
441 NativeMongoCollection_set_mongoc_error(self, &error);
442 return null_NativeMongoCursor();
443 }
444 return NativeMongoCursor_as_nullable(cursor);
445 `}
446
447 # Wrapper for `mongoc_collection_aggregate()`.
448 #
449 # This function shall execute an aggregation `pipeline` on the underlying collection.
450 #
451 # The `pipeline` parameter should contain a field named `pipeline` containing
452 # a BSON array of pipeline stages.
453 fun aggregate(pipeline: NativeBSON): nullable NativeMongoCursor import
454 NativeMongoCursor.as nullable, set_mongoc_error `{
455 bson_error_t error;
456 mongoc_cursor_t *cursor;
457 cursor = mongoc_collection_aggregate(self, MONGOC_QUERY_NONE, pipeline, NULL, NULL);
458 if (mongoc_cursor_error(cursor, &error)) {
459 NativeMongoCollection_set_mongoc_error(self, &error);
460 return null_NativeMongoCursor();
461 }
462 return NativeMongoCursor_as_nullable(cursor);
463 `}
464
465 # Wrapper for `mongoc_collection_stats()`.
466 #
467 # This function is a helper to retrieve statistics about the collection.
468 fun stats: nullable NativeBSON import set_mongoc_error, NativeBSON.as nullable `{
469 bson_error_t error;
470 bson_t *reply = bson_new();
471 if(!mongoc_collection_stats(self, NULL, reply, &error)){
472 NativeMongoCollection_set_mongoc_error(self, &error);
473 return null_NativeBSON();
474 }
475 return NativeBSON_as_nullable(reply);
476 `}
477
478 # Wrapper for `mongoc_collection_drop()`.
479 #
480 # This function requests that the `collection` be dropped,
481 # including all indexes associated with the collection.
482 fun drop: Bool import set_mongoc_error `{
483 bson_error_t error;
484 if(!mongoc_collection_drop(self, &error)) {
485 NativeMongoCollection_set_mongoc_error(self, &error);
486 return false;
487 }
488 return true;
489 `}
490
491 # Wrapper for `mongoc_collection_rename()`.
492 #
493 # This function is a helper to rename an existing collection on a MongoDB server.
494 # The name of the collection will also be updated internally so it is safe
495 # to continue using this collection after the rename.
496 # Additional operations will occur on renamed collection.
497 fun rename(new_database, new_name: CString): Bool `{
498 bson_error_t error;
499 if(!mongoc_collection_rename(self, new_database, new_name, false, &error)){
500 NativeMongoCollection_set_mongoc_error(self, &error);
501 return false;
502 }
503 return true;
504 `}
505
506 # Wrapper for `mongoc_collection_destroy()`.
507 #
508 # This instance should not be used beyond this point!
509 fun destroy `{ mongoc_collection_destroy(self); `}
510
511 # Utility method to set `Sys.last_mongoc_last_id`.
512 fun set_mongoc_last_id(id: BSONObjectId) do sys.last_mongoc_id = id
513
514 # Utility method to set `Sys.last_mongoc_error`.
515 fun set_mongoc_error(err: BSONError) do sys.last_mongoc_error = err
516 end
517
518 # Wrapper for `mongoc_cursor_t`.
519 #
520 # `mongoc_cursor_t` provides access to a MongoDB query cursor.
521 # It wraps up the wire protocol negotation required to initiate a query and
522 # retreive an unknown number of documents.
523 #
524 # Cursors are lazy, meaning that no network traffic occurs until the first call
525 # to mongoc_cursor_next().
526 #
527 # At that point we can:
528 # * Retreive more records with repeated calls to `mongoc_cursor_next()`.
529 # * Test for more records with `mongoc_cursor_more()`.
530 # * Retrieve the document under the cursor with `mongoc_cursor_current()`.
531 #
532 # See [`mongoc_cursor_t`](http://api.mongodb.org/c/current/mongoc_cursor_t.html).
533 extern class NativeMongoCursor `{ mongoc_cursor_t* `}
534
535 # Wrapper for `mongoc_cursor_current()`.
536 #
537 # Fetches the cursors current document or NULL if there has been an error.
538 fun current: NativeBSON `{
539 // As said in documentation, BSON objects should not be freed manually.
540 bson_t* bson = (bson_t*) mongoc_cursor_current(self);
541 // Copy BSON so we can let the GC free it automatically.
542 return bson_copy(bson);
543 `}
544
545 # Wrapper for `mongoc_cursor_next()`.
546 #
547 # This function shall iterate the underlying cursor, setting `current` to the next
548 # document.
549 #
550 # This function is a blocking function.
551 fun next: Bool `{
552 const bson_t *doc;
553 return mongoc_cursor_next(self, &doc);
554 `}
555
556 # Wrapper for `mongoc_cursor_destroy()`.
557 #
558 # This instance should not be used beyond this point!
559 fun destroy `{ mongoc_cursor_destroy(self); `}
560 end