summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-12-02 10:06:21 +0100
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-12-02 10:06:21 +0100
commitfd841e416881cc0392e61ec312c1870f3a0004bd (patch)
tree8357ba56e79d614ba57f722e7878b853591dc339 /docs
Initial import of libmongo-client version 0.1.8-2
Diffstat (limited to 'docs')
-rw-r--r--docs/Makefile.am2
-rw-r--r--docs/tutorial/Makefile.am13
-rw-r--r--docs/tutorial/examples/GNUmakefile36
-rw-r--r--docs/tutorial/examples/tut_bson_build.c81
-rw-r--r--docs/tutorial/examples/tut_bson_build.json16
-rw-r--r--docs/tutorial/examples/tut_bson_traverse.c123
-rw-r--r--docs/tutorial/examples/tut_hl_client.c107
-rw-r--r--docs/tutorial/examples/tut_json2bson.c132
-rw-r--r--docs/tutorial/examples/tut_mongo_sync.c273
-rw-r--r--docs/tutorial/examples/tut_mongo_sync_cmd_create.c82
-rw-r--r--docs/tutorial/examples/tut_mongo_sync_cmd_custom.c81
-rw-r--r--docs/tutorial/examples/tut_mongo_sync_cmd_index_create.c54
-rw-r--r--docs/tutorial/tut_bson.h10
-rw-r--r--docs/tutorial/tut_bson_build.h62
-rw-r--r--docs/tutorial/tut_bson_traverse.h135
-rw-r--r--docs/tutorial/tut_hl_client.h86
-rw-r--r--docs/tutorial/tut_json2bson.h97
-rw-r--r--docs/tutorial/tut_mongo_sync.h16
-rw-r--r--docs/tutorial/tut_mongo_sync_cmd_create.h53
-rw-r--r--docs/tutorial/tut_mongo_sync_cmd_custom.h64
-rw-r--r--docs/tutorial/tut_mongo_sync_cmd_index_create.h66
-rw-r--r--docs/tutorial/tut_mongo_sync_connect.h49
-rw-r--r--docs/tutorial/tut_mongo_sync_insert.h46
-rw-r--r--docs/tutorial/tut_mongo_sync_query.h67
-rw-r--r--docs/tutorial/tut_mongo_sync_query_complex.h43
-rw-r--r--docs/tutorial/tutorial.h34
26 files changed, 1828 insertions, 0 deletions
diff --git a/docs/Makefile.am b/docs/Makefile.am
new file mode 100644
index 0000000..11996c1
--- /dev/null
+++ b/docs/Makefile.am
@@ -0,0 +1,2 @@
+SUBDIRS = tutorial
+
diff --git a/docs/tutorial/Makefile.am b/docs/tutorial/Makefile.am
new file mode 100644
index 0000000..4ebd301
--- /dev/null
+++ b/docs/tutorial/Makefile.am
@@ -0,0 +1,13 @@
+EXTRA_DIST = tutorial.h \
+ examples/GNUmakefile \
+ tut_bson.h \
+ tut_bson_build.h examples/tut_bson_build.c examples/tut_bson_build.json \
+ tut_bson_traverse.h examples/tut_bson_traverse.c \
+ tut_mongo_sync.h \
+ tut_mongo_sync_connect.h tut_mongo_sync_insert.h \
+ tut_mongo_sync_query.h tut_mongo_sync_query_complex.h \
+ examples/tut_mongo_sync.c \
+ tut_mongo_sync_cmd_create.h \
+ examples/tut_mongo_sync_cmd_create.c \
+ tut_hl_client.h examples/tut_hl_client.c \
+ tut_json2bson.h examples/tut_json2bson.c
diff --git a/docs/tutorial/examples/GNUmakefile b/docs/tutorial/examples/GNUmakefile
new file mode 100644
index 0000000..01b5363
--- /dev/null
+++ b/docs/tutorial/examples/GNUmakefile
@@ -0,0 +1,36 @@
+# NOTE: This Makefile assumes that a recent enough version of
+# libmongo-client is installed!
+#
+# It will NOT work in the build directory, without an installed
+# libmongo-client library.
+
+TUTORIAL_PROGRAMS = tut/bson_build \
+ tut/bson_traverse \
+ tut/mongo_sync \
+ tut/mongo_sync_cmd_create \
+ tut/mongo_sync_cmd_custom \
+ tut/mongo_sync_cmd_index_create \
+ tut/hl_client \
+ tut/json2bson
+
+LMC_CFLAGS = $(shell pkg-config --cflags libmongo-client)
+LMC_LIBS = $(shell pkg-config --libs libmongo-client)
+
+JSON_C_CFLAGS = $(shell pkg-config --cflags json)
+JSON_C_LIBS = $(shell pkg-config --libs json)
+
+TUT_CFLAGS = ${LMC_CFLAGS}
+TUT_LIBS = ${LMC_LIBS}
+
+all: ${TUTORIAL_PROGRAMS}
+clean:
+ rm -f ${TUTORIAL_PROGRAMS}
+ -rmdir tut/
+
+tut/json2bson: TUT_CFLAGS += ${JSON_C_CFLAGS}
+tut/json2bson: TUT_LIBS += ${JSON_C_LIBS}
+${TUTORIAL_PROGRAMS}: tut/%: tut_%.c
+ @install -d tut
+ ${CC} ${TUT_CFLAGS} ${CFLAGS} $< ${TUT_LIBS} ${LDFLAGS} -o $@
+
+.PHONY: all clean
diff --git a/docs/tutorial/examples/tut_bson_build.c b/docs/tutorial/examples/tut_bson_build.c
new file mode 100644
index 0000000..2624310
--- /dev/null
+++ b/docs/tutorial/examples/tut_bson_build.c
@@ -0,0 +1,81 @@
+#include <mongo.h>
+
+#include <string.h>
+#include <stdio.h>
+
+int
+main (void)
+{
+ bson *b_new, *b_builder, *b_builder_full;
+ bson *page1, *page2, *pages;
+
+ page1 = bson_new ();
+ bson_append_string (page1, "title", "BSON tutorial", -1);
+ bson_append_string (page1, "content", "...", -1);
+ bson_append_int32 (page1, "importance", 1);
+ bson_finish (page1);
+
+ page2 = bson_new ();
+ bson_append_string (page2, "title", "Some other thing", -1);
+ bson_append_string (page2, "content", "...", -1);
+ bson_append_int32 (page2, "importance", 0);
+ bson_finish (page2);
+
+ pages = bson_new ();
+ bson_append_document (pages, "1", page1);
+ bson_append_document (pages, "2", page2);
+ bson_finish (pages);
+
+ b_new = bson_new ();
+ bson_append_string (b_new, "author", "Gergely Nagy", -1);
+ bson_append_array (b_new, "pages", pages);
+ bson_append_boolean (b_new, "inline", TRUE);
+ bson_finish (b_new);
+
+ b_builder = bson_build (BSON_TYPE_STRING, "author", "Gergely Nagy", -1,
+ BSON_TYPE_ARRAY, "pages", pages,
+ BSON_TYPE_BOOLEAN, "inline", TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (b_builder);
+
+ b_builder_full = bson_build_full
+ (BSON_TYPE_STRING, "author", FALSE, "Gergely Nagy", -1,
+ BSON_TYPE_ARRAY, "pages", TRUE,
+ bson_build_full (BSON_TYPE_DOCUMENT, "1", TRUE,
+ bson_build (BSON_TYPE_STRING, "title", "BSON tutorial", -1,
+ BSON_TYPE_STRING, "content", "...", -1,
+ BSON_TYPE_INT32, "importance", 1,
+ BSON_TYPE_NONE),
+ BSON_TYPE_DOCUMENT, "2", TRUE,
+ bson_build (BSON_TYPE_STRING, "title", "Some other thing", -1,
+ BSON_TYPE_STRING, "content", "...", -1,
+ BSON_TYPE_INT32, "importance", 0,
+ BSON_TYPE_NONE),
+ BSON_TYPE_NONE),
+ BSON_TYPE_BOOLEAN, "inline", FALSE, TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (b_builder_full);
+
+ if (bson_size (b_new) != bson_size (b_builder) ||
+ bson_size (b_new) != bson_size (b_builder_full))
+ {
+ fprintf (stderr, "There's something fishy: the three BSON objects have different sizes");
+ return 1;
+ }
+
+ if (memcmp (bson_data (b_new), bson_data (b_builder), bson_size (b_new)) != 0 ||
+ memcmp (bson_data (b_new), bson_data (b_builder_full), bson_size (b_new)) != 0)
+ {
+ fprintf (stderr, "The BSON objects do not match. Something smells.");
+ return 1;
+ }
+
+ bson_free (b_builder_full);
+ bson_free (b_builder);
+ bson_free (b_new);
+ bson_free (pages);
+ bson_free (page2);
+ bson_free (page1);
+
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_bson_build.json b/docs/tutorial/examples/tut_bson_build.json
new file mode 100644
index 0000000..078cf53
--- /dev/null
+++ b/docs/tutorial/examples/tut_bson_build.json
@@ -0,0 +1,16 @@
+{
+ author: "Gergely Nagy",
+ pages: [
+ {
+ title: "BSON tutorial",
+ content: "...",
+ importance: 1
+ },
+ {
+ title: "Some other thing",
+ content: "...",
+ importance: 0
+ }
+ ],
+ inline: true
+}
diff --git a/docs/tutorial/examples/tut_bson_traverse.c b/docs/tutorial/examples/tut_bson_traverse.c
new file mode 100644
index 0000000..4be7b1d
--- /dev/null
+++ b/docs/tutorial/examples/tut_bson_traverse.c
@@ -0,0 +1,123 @@
+#include <mongo.h>
+
+#include <string.h>
+#include <stdio.h>
+
+bson *
+tut_bson (void)
+{
+ bson *b;
+
+ b = bson_build_full
+ (BSON_TYPE_STRING, "author", FALSE, "Gergely Nagy", -1,
+ BSON_TYPE_ARRAY, "pages", TRUE,
+ bson_build_full (BSON_TYPE_DOCUMENT, "1", TRUE,
+ bson_build (BSON_TYPE_STRING, "title", "BSON tutorial", -1,
+ BSON_TYPE_STRING, "content", "...", -1,
+ BSON_TYPE_INT32, "importance", 1,
+ BSON_TYPE_NONE),
+ BSON_TYPE_DOCUMENT, "2", TRUE,
+ bson_build (BSON_TYPE_STRING, "title", "Some other thing", -1,
+ BSON_TYPE_STRING, "content", "...", -1,
+ BSON_TYPE_INT32, "importance", 0,
+ BSON_TYPE_NONE),
+ BSON_TYPE_NONE),
+ BSON_TYPE_BOOLEAN, "inline", FALSE, TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (b);
+
+ return b;
+}
+
+int
+main (void)
+{
+ bson *doc;
+ bson_cursor *c, *c_arr, *c_page;
+
+ bson *v_doc, *v_array;
+ gboolean v_bool;
+ const gchar *v_str;
+
+ doc = tut_bson ();
+
+ c = bson_find (doc, "author");
+ bson_cursor_get_string (c, &v_str);
+ printf ("Author: %s\n", v_str);
+
+ bson_cursor_next (c);
+ bson_cursor_next (c);
+
+ bson_cursor_get_boolean (c, &v_bool);
+ printf ("inline: %s\n", (v_bool) ? "TRUE" : "FALSE");
+
+ bson_cursor_free (c);
+
+ c = bson_find (doc, "author");
+ bson_cursor_get_string (c, &v_str);
+ bson_cursor_free (c);
+ c = bson_find (doc, "inline");
+ bson_cursor_get_boolean (c, &v_bool);
+ bson_cursor_free (c);
+
+ printf ("Author: %s; inline: %s; (bson_find)\n",
+ v_str, (v_bool) ? "TRUE" : "FALSE");
+
+ c = bson_find (doc, "author");
+ bson_cursor_get_string (c, &v_str);
+ while (bson_cursor_next (c))
+ {
+ if (strcmp (bson_cursor_key (c), "inline") == 0)
+ {
+ bson_cursor_get_boolean (c, &v_bool);
+ break;
+ }
+ }
+ bson_cursor_free (c);
+
+ printf ("Author: %s; inline: %s; (bson_cursor_next)\n",
+ v_str, (v_bool) ? "TRUE" : "FALSE");
+
+ c = bson_find (doc, "author");
+ bson_cursor_get_string (c, &v_str);
+ bson_cursor_find_next (c, "inline");
+ bson_cursor_get_boolean (c, &v_bool);
+ bson_cursor_free (c);
+
+ printf ("Author: %s; inline: %s; (bson_cursor_find_next)\n",
+ v_str, (v_bool) ? "TRUE" : "FALSE");
+
+ c = bson_find (doc, "pages");
+ bson_cursor_find (c, "inline");
+ bson_cursor_get_boolean (c, &v_bool);
+ bson_cursor_find (c, "author");
+ bson_cursor_get_string (c, &v_str);
+ bson_cursor_free (c);
+
+ printf ("Author: %s; inline: %s; (bson_cursor_find)\n",
+ v_str, (v_bool) ? "TRUE" : "FALSE");
+
+ c = bson_cursor_new (doc);
+ while (bson_cursor_next (c))
+ {
+ printf ("Key: %s; type=%s\n", bson_cursor_key (c),
+ bson_cursor_type_as_string (c));
+ }
+ bson_cursor_free (c);
+
+ c = bson_find (doc, "pages");
+ bson_cursor_get_array (c, &v_array);
+ c_arr = bson_find (v_array, "2");
+ bson_cursor_get_document (c_arr, &v_doc);
+ c_page = bson_find (v_doc, "title");
+ bson_cursor_get_string (c_page, &v_str);
+
+ bson_cursor_free (c_page);
+ bson_cursor_free (c_arr);
+ bson_cursor_free (c);
+
+ printf ("Title of the 2nd page in the pages array: %s\n", v_str);
+
+ bson_free (doc);
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_hl_client.c b/docs/tutorial/examples/tut_hl_client.c
new file mode 100644
index 0000000..68ceb8f
--- /dev/null
+++ b/docs/tutorial/examples/tut_hl_client.c
@@ -0,0 +1,107 @@
+#include <mongo.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+
+static void
+do_inserts (mongo_sync_connection *conn)
+{
+ bson *base;
+ gint i;
+
+ base = bson_build
+ (BSON_TYPE_STRING, "tutorial-program", "tut_hl_client.c", -1,
+ BSON_TYPE_INT32, "the answer to life, the universe and everything", 42,
+ BSON_TYPE_NONE);
+ bson_finish (base);
+
+ for (i = 0; i < 1000; i++)
+ {
+ bson *n;
+
+ n = bson_new_from_data (bson_data (base), bson_size (base) - 1);
+ bson_append_int32 (n, "counter", i);
+ bson_finish (n);
+
+ if (!mongo_sync_cmd_insert (conn, "lmc.tutorial", n, NULL))
+ {
+ fprintf (stderr, "Error inserting document %d: %s\n", i,
+ strerror (errno));
+ exit (1);
+ }
+ bson_free (n);
+ }
+ bson_free (base);
+}
+
+static void
+do_query (mongo_sync_connection *conn)
+{
+ mongo_sync_cursor *c;
+ bson *query;
+ gchar *error = NULL;
+
+ query = bson_build
+ (BSON_TYPE_STRING, "tutorial-program", "tut_hl_client.c", -1,
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ c = mongo_sync_cursor_new (conn, "lmc.tutorial",
+ mongo_sync_cmd_query (conn, "lmc.tutorial", 0,
+ 0, 10, query, NULL));
+ if (!c)
+ {
+ fprintf (stderr, "Error creating the query cursor: %s\n",
+ strerror (errno));
+ exit (1);
+ }
+ bson_free (query);
+
+ while (mongo_sync_cursor_next (c))
+ {
+ bson *b = mongo_sync_cursor_get_data (c);
+ bson_cursor *bc;
+ gint32 cnt;
+
+ if (!b)
+ {
+ int e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, "lmc", &error);
+ fprintf (stderr, "Error retrieving cursor data: %s\n",
+ (error) ? error : strerror (e));
+ exit (1);
+ }
+
+ bc = bson_find (b, "counter");
+ bson_cursor_get_int32 (bc, &cnt);
+ printf ("\rCounter: %d", cnt);
+
+ bson_cursor_free (bc);
+ bson_free (b);
+ }
+ printf ("\n");
+
+ mongo_sync_cursor_free (c);
+}
+
+int
+main (void)
+{
+ mongo_sync_connection *conn;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ fprintf (stderr, "Connection failed: %s\n", strerror (errno));
+ return 1;
+ }
+
+ do_inserts (conn);
+ do_query (conn);
+
+ mongo_sync_disconnect (conn);
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_json2bson.c b/docs/tutorial/examples/tut_json2bson.c
new file mode 100644
index 0000000..3ad5b9a
--- /dev/null
+++ b/docs/tutorial/examples/tut_json2bson.c
@@ -0,0 +1,132 @@
+#define __STRICT_ANSI__ 1
+
+#include <bson.h>
+#include <json.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <glib.h>
+
+static bson *json_to_bson (struct json_object *json);
+
+static void
+json_key_to_bson_key (bson *b, void *val,
+ const gchar *key)
+{
+ switch (json_object_get_type (val))
+ {
+ case json_type_boolean:
+ bson_append_boolean (b, key, json_object_get_boolean (val));
+ break;
+ case json_type_double:
+ bson_append_double (b, key, json_object_get_double (val));
+ break;
+ case json_type_int:
+ bson_append_int32 (b, key, json_object_get_int (val));
+ break;
+ case json_type_string:
+ bson_append_string (b, key, json_object_get_string (val), -1);
+ break;
+ case json_type_object:
+ {
+ bson *sub;
+
+ sub = json_to_bson (val);
+ bson_append_document (b, key, sub);
+ bson_free (sub);
+ break;
+ }
+ case json_type_array:
+ {
+ gint pos;
+ bson *sub;
+
+ sub = bson_new ();
+
+ for (pos = 0; pos < json_object_array_length (val); pos++)
+ {
+ gchar *nk = g_strdup_printf ("%d", pos);
+
+ json_key_to_bson_key (sub, json_object_array_get_idx (val, pos),
+ nk);
+ g_free (nk);
+ }
+ bson_finish (sub);
+
+ bson_append_array (b, key, sub);
+ bson_free (sub);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static void
+json_to_bson_foreach (bson *b, struct json_object *json)
+{
+ json_object_object_foreach (json, key, val)
+ {
+ json_key_to_bson_key (b, val, key);
+ }
+}
+
+static bson *
+json_to_bson (struct json_object *json)
+{
+ bson *b;
+
+ b = bson_new ();
+ json_to_bson_foreach (b, json);
+ bson_finish (b);
+
+ return b;
+}
+
+int
+main (int argc, char **argv)
+{
+ GIOChannel *input;
+ GString *json_str;
+ GError *error = NULL;
+ struct json_tokener *tokener;
+
+ input = g_io_channel_unix_new (0);
+
+ json_str = g_string_new (NULL);
+ tokener = json_tokener_new ();
+
+ while (g_io_channel_read_line_string (input, json_str,
+ NULL, &error) == G_IO_STATUS_NORMAL)
+ {
+ struct json_object *json;
+ bson *bson;
+
+ json_tokener_reset (tokener);
+
+ json = json_tokener_parse_ex (tokener, json_str->str, json_str->len);
+ if (!json)
+ {
+ fprintf (stderr, "Error parsing json: %s\n", json_str->str);
+ break;
+ }
+
+ if (json_object_get_type (json) != json_type_object)
+ {
+ fprintf (stderr,
+ "Error: json's top-level object is not object: %s\n",
+ json_str->str);
+ json_object_put (json);
+ break;
+ }
+
+ bson = json_to_bson (json);
+ json_object_put (json);
+
+ write (1, bson_data (bson), bson_size (bson));
+
+ bson_free (bson);
+ }
+
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_mongo_sync.c b/docs/tutorial/examples/tut_mongo_sync.c
new file mode 100644
index 0000000..ff27560
--- /dev/null
+++ b/docs/tutorial/examples/tut_mongo_sync.c
@@ -0,0 +1,273 @@
+#include <mongo.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+void
+tut_sync_connect (void)
+{
+ mongo_sync_connection *conn;
+
+ conn = mongo_sync_connect ("localhost", 27017, TRUE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ exit (1);
+ }
+ mongo_sync_disconnect (conn);
+}
+
+void
+tut_sync_connect_replica (void)
+{
+ mongo_sync_connection *conn;
+
+ conn = mongo_sync_connect ("mongo-master", 27017, TRUE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ return;
+ }
+
+ if (!mongo_sync_conn_set_auto_reconnect (conn, TRUE))
+ {
+ perror ("mongo_sync_conn_set_auto_reconnect()");
+ return;
+ }
+
+ if (!mongo_sync_conn_seed_add (conn, "mongo-replica", 27017))
+ {
+ perror ("mongo_sync_conn_seed_add()");
+ return;
+ }
+ if (!mongo_sync_conn_seed_add (conn, "mongo-replica-2", 27017))
+ {
+ perror ("mongo_sync_conn_seed_add()");
+ return;
+ }
+
+ mongo_sync_disconnect (conn);
+}
+
+void
+tut_sync_insert (void)
+{
+ mongo_sync_connection *conn;
+ bson *doc1, *doc2, *doc3;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ exit (1);
+ }
+
+ doc1 = bson_build (BSON_TYPE_STRING, "hello", "world", -1,
+ BSON_TYPE_INT32, "the_final_answer", 42,
+ BSON_TYPE_BOOLEAN, "yes?", FALSE,
+ BSON_TYPE_INT32, "n", 1,
+ BSON_TYPE_NONE);
+ bson_finish (doc1);
+
+ if (!mongo_sync_cmd_insert (conn, "tutorial.docs", doc1, NULL))
+ {
+ perror ("mongo_sync_cmd_insert()");
+ exit (1);
+ }
+
+ doc2 = bson_build (BSON_TYPE_INT32, "n", 2,
+ BSON_TYPE_BOOLEAN, "yes?", FALSE,
+ BSON_TYPE_STRING, "hello", "dolly", -1,
+ BSON_TYPE_NONE);
+ bson_finish (doc2);
+
+ doc3 = bson_build (BSON_TYPE_INT32, "n", 3,
+ BSON_TYPE_STRING, "hello", "nurse", -1,
+ BSON_TYPE_BOOLEAN, "yes?", TRUE,
+ BSON_TYPE_NONE);
+ bson_finish (doc3);
+
+ if (!mongo_sync_cmd_insert (conn, "tutorial.docs", doc2, doc3, NULL))
+ {
+ perror ("mongo_sync_cmd_insert()");
+ exit (1);
+ }
+
+ bson_free (doc3);
+ bson_free (doc2);
+ bson_free (doc1);
+
+ mongo_sync_disconnect (conn);
+}
+
+void
+tut_sync_query_simple (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *cursor;
+ bson *query;
+ gint i = 0;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ exit (1);
+ }
+
+ query = bson_new ();
+ bson_finish (query);
+
+ p = mongo_sync_cmd_query (conn, "tutorial.docs", 0,
+ 0, 10, query, NULL);
+ if (!p)
+ {
+ perror ("mongo_sync_cmd_query()");
+ exit (1);
+ }
+ bson_free (query);
+
+ cursor = mongo_sync_cursor_new (conn, "tutorial.docs", p);
+ if (!cursor)
+ {
+ perror ("mongo_sync_cursor_new()");
+ exit (1);
+ }
+
+ while (mongo_sync_cursor_next (cursor))
+ {
+ bson *result = mongo_sync_cursor_get_data (cursor);
+ bson_cursor *c;
+
+ if (!result)
+ {
+ perror ("mongo_sync_cursor_get_data()");
+ exit (1);
+ }
+
+ printf ("Keys in document #%d:\n", i);
+ c = bson_cursor_new (result);
+ while (bson_cursor_next (c))
+ printf ("\t%s\n", bson_cursor_key (c));
+
+ i++;
+ bson_cursor_free (c);
+ bson_free (result);
+ }
+
+ mongo_sync_cursor_free (cursor);
+ mongo_sync_disconnect (conn);
+}
+
+void
+tut_sync_query_complex (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *cursor;
+ bson *query, *select;
+ gint i = 0;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ exit (1);
+ }
+
+ query = bson_build_full (BSON_TYPE_DOCUMENT, "$query", TRUE,
+ bson_build (BSON_TYPE_BOOLEAN, "yes?", FALSE,
+ BSON_TYPE_NONE),
+ BSON_TYPE_DOCUMENT, "$orderby", TRUE,
+ bson_build (BSON_TYPE_INT32, "n", 1,
+ BSON_TYPE_NONE),
+ BSON_TYPE_NONE);
+ bson_finish (query);
+
+ select = bson_build (BSON_TYPE_INT32, "hello", 1,
+ BSON_TYPE_INT32, "n", 1,
+ BSON_TYPE_INT32, "yes?", 1,
+ BSON_TYPE_NONE);
+ bson_finish (select);
+
+ p = mongo_sync_cmd_query (conn, "tutorial.docs", 0,
+ 0, 10, query, select);
+ if (!p)
+ {
+ perror ("mongo_sync_cmd_query()");
+ exit (1);
+ }
+ bson_free (query);
+ bson_free (select);
+
+ cursor = mongo_sync_cursor_new (conn, "tutorial.docs", p);
+ if (!cursor)
+ {
+ perror ("mongo_sync_cursor_new()");
+ exit (1);
+ }
+
+ while (mongo_sync_cursor_next (cursor))
+ {
+ const char *hello;
+ gint32 n;
+ gboolean yes;
+
+ bson *result;
+ bson_cursor *c;
+
+ result = mongo_sync_cursor_get_data (cursor);
+ if (!result)
+ {
+ perror ("mongo_sync_cursor_get_data()");
+ exit (1);
+ }
+
+ c = bson_find (result, "hello");
+ if (!bson_cursor_get_string (c, &hello))
+ {
+ perror ("bson_cursor_get_string()");
+ exit (1);
+ }
+ bson_cursor_free (c);
+
+ c = bson_find (result, "n");
+ if (!bson_cursor_get_int32 (c, &n))
+ {
+ perror ("bson_cursor_get_int32()");
+ exit (1);
+ }
+ bson_cursor_free (c);
+
+ c = bson_find (result, "yes?");
+ if (!bson_cursor_get_boolean (c, &yes))
+ {
+ perror ("bson_cursor_get_boolean()");
+ exit (1);
+ }
+ bson_cursor_free (c);
+
+ printf ("Document #%d: hello=%s; n=%d; yes?=%s\n",
+ i, hello, n, (yes) ? "TRUE" : "FALSE");
+
+ bson_free (result);
+ i++;
+ }
+
+ mongo_sync_cursor_free (cursor);
+ mongo_sync_disconnect (conn);
+}
+
+int
+main (int argc, char *argv[])
+{
+ tut_sync_connect ();
+ tut_sync_connect_replica ();
+ tut_sync_insert ();
+ tut_sync_query_simple ();
+ tut_sync_query_complex ();
+
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_mongo_sync_cmd_create.c b/docs/tutorial/examples/tut_mongo_sync_cmd_create.c
new file mode 100644
index 0000000..9b31c91
--- /dev/null
+++ b/docs/tutorial/examples/tut_mongo_sync_cmd_create.c
@@ -0,0 +1,82 @@
+#include <mongo.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+static void
+print_coll_info (bson *info)
+{
+ bson_cursor *c = NULL;
+ bson *options = NULL;
+
+ const gchar *name;
+ gboolean capped = FALSE;
+ gint64 size = -1;
+ gint64 max = -1;
+
+ c = bson_find (info, "name");
+ bson_cursor_get_string (c, &name);
+ bson_cursor_find (c, "options");
+
+ bson_cursor_get_document (c, &options);
+
+ printf ("Options for %s:\n", name);
+
+ bson_cursor_free (c);
+ bson_free (info);
+
+ c = bson_find (options, "capped");
+ bson_cursor_get_boolean (c, &capped);
+ bson_cursor_free (c);
+
+ c = bson_find (options, "size");
+ bson_cursor_get_int64 (c, &size);
+ bson_cursor_free (c);
+
+ c = bson_find (options, "max");
+ bson_cursor_get_int64 (c, &max);
+ bson_cursor_free (c);
+
+ bson_free (options);
+
+ printf ("\tCapped: %s\n", (capped) ? "yes" : "no");
+ if (size > 0)
+ printf ("\tSize : %lu\n", size);
+ if (max > 0)
+ printf ("\tMax : %lu\n", max);
+ printf ("\n");
+}
+
+int
+main (void)
+{
+ mongo_sync_connection *conn;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ fprintf (stderr, "Connection failed: %s\n", strerror (errno));
+ return 1;
+ }
+
+ mongo_sync_cmd_create (conn, "lmc", "cmd_create", MONGO_COLLECTION_DEFAULTS);
+ print_coll_info (mongo_sync_cmd_exists (conn, "lmc", "cmd_create"));
+
+ mongo_sync_cmd_create (conn, "lmc", "cmd_create_capped",
+ MONGO_COLLECTION_CAPPED, 655360);
+ print_coll_info (mongo_sync_cmd_exists (conn, "lmc", "cmd_create_capped"));
+
+ mongo_sync_cmd_create (conn, "lmc", "cmd_create_capped_max",
+ MONGO_COLLECTION_CAPPED | MONGO_COLLECTION_CAPPED_MAX,
+ 655360, 100);
+ print_coll_info (mongo_sync_cmd_exists (conn, "lmc",
+ "cmd_create_capped_max"));
+
+ mongo_sync_cmd_create (conn, "lmc", "cmd_create_sized",
+ MONGO_COLLECTION_SIZED, 655360);
+ print_coll_info (mongo_sync_cmd_exists (conn, "lmc", "cmd_create_sized"));
+
+ mongo_sync_disconnect (conn);
+
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_mongo_sync_cmd_custom.c b/docs/tutorial/examples/tut_mongo_sync_cmd_custom.c
new file mode 100644
index 0000000..4e48b18
--- /dev/null
+++ b/docs/tutorial/examples/tut_mongo_sync_cmd_custom.c
@@ -0,0 +1,81 @@
+#include <mongo.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+ mongo_sync_connection *conn;
+ mongo_packet *p;
+ mongo_sync_cursor *cursor;
+ bson *eval;
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ perror ("mongo_sync_connect()");
+ exit (1);
+ }
+
+ eval = bson_build_full (BSON_TYPE_JS_CODE, "$eval", FALSE,
+ "function(x){return x + 4.2;}", -1,
+ BSON_TYPE_ARRAY, "args", TRUE,
+ bson_build (BSON_TYPE_INT32, "0", 1,
+ BSON_TYPE_NONE),
+ BSON_TYPE_NONE);
+ bson_finish (eval);
+
+ p = mongo_sync_cmd_custom (conn, "test", eval);
+
+ if (!p)
+ {
+ gchar *error = NULL;
+
+ mongo_sync_cmd_get_last_error (conn, "test", &error);
+ fprintf (stderr, "Can't run db.eval: %s\n", error);
+ g_free (error);
+
+ exit (1);
+ }
+
+ cursor = mongo_sync_cursor_new (conn, "test", p);
+
+ if (!cursor)
+ {
+ perror ("mongo_sync_cursor_new()");
+ exit (1);
+ }
+
+ while (mongo_sync_cursor_next (cursor))
+ {
+ bson *result;
+ bson_cursor *c;
+ gdouble r;
+
+ result = mongo_sync_cursor_get_data (cursor);
+ if (!result)
+ {
+ perror ("mongo_sync_cursor_get_data()");
+ exit (1);
+ }
+
+ c = bson_find (result, "retval");
+ if (!bson_cursor_get_double (c, &r))
+ {
+ perror ("bson_cursor_get_double()");
+ exit (1);
+ }
+ bson_cursor_free (c);
+ bson_free (result);
+
+ printf ("Result: %2.1f\n", r);
+ }
+
+ mongo_sync_cursor_free (cursor);
+ mongo_sync_disconnect (conn);
+
+ return 0;
+}
diff --git a/docs/tutorial/examples/tut_mongo_sync_cmd_index_create.c b/docs/tutorial/examples/tut_mongo_sync_cmd_index_create.c
new file mode 100644
index 0000000..0e2f0b5
--- /dev/null
+++ b/docs/tutorial/examples/tut_mongo_sync_cmd_index_create.c
@@ -0,0 +1,54 @@
+#include <mongo.h>
+
+#include <errno.h>
+#include <stdio.h>
+
+static void
+create_and_verify_index(mongo_sync_connection *conn,
+ bson *index)
+{
+ if (!mongo_sync_cmd_index_create (conn, "lmc.indexed", index,
+ MONGO_INDEX_UNIQUE | MONGO_INDEX_DROP_DUPS |
+ MONGO_INDEX_SPARSE))
+ {
+ gchar *error = NULL;
+ int e = errno;
+
+ mongo_sync_cmd_get_last_error (conn, "lmc.indexed", &error);
+ fprintf (stderr, "Can't create indexes: %s\n", error ? error : strerror (e));
+ g_free (error);
+ }
+ else
+ printf ("Index successfully created!\n");
+}
+
+int
+main (void)
+{
+ mongo_sync_connection *conn;
+ bson *invalid_index, *index;
+
+ invalid_index = bson_build (BSON_TYPE_STRING, "name", "", -1,
+ BSON_TYPE_NONE);
+ bson_finish (invalid_index);
+
+ index = bson_build (BSON_TYPE_INT32, "name", 1,
+ BSON_TYPE_NONE);
+ bson_finish (index);
+
+ conn = mongo_sync_connect ("localhost", 27017, FALSE);
+ if (!conn)
+ {
+ fprintf (stderr, "Connection failed: %s\n", strerror (errno));
+ return 1;
+ }
+
+ create_and_verify_index (conn, invalid_index);
+ create_and_verify_index (conn, index);
+
+ bson_free (invalid_index);
+ bson_free (index);
+ mongo_sync_disconnect (conn);
+
+ return 0;
+}
diff --git a/docs/tutorial/tut_bson.h b/docs/tutorial/tut_bson.h
new file mode 100644
index 0000000..973f12d
--- /dev/null
+++ b/docs/tutorial/tut_bson.h
@@ -0,0 +1,10 @@
+/** @page tut_bson Working with BSON objects
+ *
+ * In this section, we'll cover the basics of working with BSON
+ * objects in a few big steps. Working with BSON is fairly
+ * straightforward, so we will not be going into much details here.
+ *
+ * Contents:
+ * - @subpage tut_bson_build
+ * - @subpage tut_bson_traverse
+ */
diff --git a/docs/tutorial/tut_bson_build.h b/docs/tutorial/tut_bson_build.h
new file mode 100644
index 0000000..5c5eb54
--- /dev/null
+++ b/docs/tutorial/tut_bson_build.h
@@ -0,0 +1,62 @@
+/** @page tut_bson_build Building BSON objects
+ *
+ * Our first task will be to build a BSON document, which we can later
+ * insert into MongoDB. For this example, we want something more
+ * complex than a simple "Hello World"-style object, so we can
+ * showcase all the interesting functions of the BSON API.
+ *
+ * Lets build a document that would look like this, if we were writing
+ * JSON:
+ * @verbinclude tut_bson_build.json
+ *
+ * @dontinclude tut_bson_build.c
+ *
+ * First we start by including the main libmongo-client header. It's
+ * convenient to include the whole lot instead of including the used
+ * headers one by one, unless one's embedding only parts of the
+ * library.
+ * @until mongo.h
+ *
+ * @until {
+ *
+ * We'll be building the same BSON object in various different ways,
+ * so we declare a few more variables than we'd normally need.
+ * @until pages
+ *
+ * Next, we create the two pages:
+ * @until bson_finish (page2)
+ *
+ * Then we construct the "pages" array. Do note how we set the key to
+ * "1" and "2", and how pages is just a document! This is because in
+ * BSON, an array is a document that has a special type, and where
+ * keys are numbers.
+ * @until bson_finish (pages)
+ *
+ * Finally, now that we have all the subdocuments ready, we build up
+ * our main object:
+ * @until bson_finish (b_new)
+ *
+ * And that's about it! But surely, there is an easier way to do
+ * this... And indeed, there is, using bson_build():
+ * @until bson_finish (b_builder)
+ *
+ * Much cleaner, but still, we had to create the pages array in three
+ * steps beforehand. Couldn't we do it in one gigantic function call
+ * instead?
+ * @until bson_finish (b_builder_full)
+ *
+ * Wonderful! We have three BSON objects created now, in three
+ * different ways! But are they the same? That's really easy to figure
+ * out. As a quick check, we can compare their sizes: if they do not
+ * match, we can bail out fast:
+ * @until }
+ *
+ * Or, we can do a more expensive comparsion, and compare the data:
+ * @until }
+ *
+ * And now that we are done, we free up the resources we allocated.
+ * @until bson_free (page1)
+ *
+ *
+ * @until }
+ */
diff --git a/docs/tutorial/tut_bson_traverse.h b/docs/tutorial/tut_bson_traverse.h
new file mode 100644
index 0000000..712ff71
--- /dev/null
+++ b/docs/tutorial/tut_bson_traverse.h
@@ -0,0 +1,135 @@
+/** @page tut_bson_traverse Traversing BSON objects
+ *
+ * Now that we can build BSON objects (see the @ref tut_bson_build
+ * "previous section"), it is time that we learn how to find things in
+ * them!
+ *
+ * We will use the same JSON structure as in the previous example.
+ *
+ * @dontinclude tut_bson_traverse.c
+ * First, we include our stuff, and create a function that gives us a
+ * BSON object to work with:
+ * @until return b
+ * @line }
+ *
+ * @until {
+ * First, we need a variable to hold our BSON object, and a cursor,
+ * with which we can find the keys we're looking for.
+ * @until bson_cursor
+ *
+ * Then we need a few variables to store the retrieved information
+ * in. Extracting data out of a BSON object involves storing them in a
+ * variable of our own.
+ * @until v_str
+ *
+ * @until doc = tut_bson
+ *
+ * In order to find something in a BSON object, we must know the keys
+ * name. There's two ways to find information within a BSON object:
+ * bson_find() and bson_cursor_next() and its friends.
+ *
+ * The first takes a BSON object, and returns a cursor that points to
+ * the key we wanted to find (or to NULL, if it was not found, of
+ * course). We can then extract that value, and either close the
+ * cursor, or use bson_cursor_next() to iterate over the rest of the
+ * keys.
+ *
+ * The advantage of bson_find() is that we can jump to a specific key
+ * easily, but at the cost of having to use a new cursor every time,
+ * which in turn will start searching from the beginning of a BSON
+ * document.
+ *
+ * On the other hand, bson_cursor_next() remembers its position, and
+ * jumping to the next key is straightforward. It can also be used in
+ * conjunction with bson_find() to locate the first key we're
+ * interested in, and move on to the next until we're done.
+ *
+ * For our first traversal example, lets say we want to see who the
+ * author of our BSON object is! We can extract that information by
+ * locating the "author" key, and retrieving the string contents:
+ * @until printf
+ *
+ * Now, if we also want to know whether the 'inline' key is set to
+ * true or false, we have two options: if we know the exact order of
+ * keys, we can use the appropriate amount of bson_cursor_next()
+ * calls:
+ * @until printf
+ *
+ * But this is not only ugly, it's very sensitive to the order of the
+ * keys, and it's hard to understand aswell, without being familiar
+ * with the document's structure.
+ *
+ * So, while it is a little more inconvenient, it's better to find the
+ * key in some other way. But first, let's close our cursor, as we'll
+ * need to start again anyway...
+ * @until bson_cursor_free
+ *
+ * First, we'll go the easy route, and use bson_find():
+ * @until printf
+ *
+ * Now, the downside of this, is that we ran through the BSON object
+ * twice. Well, once and a little, since the "author" key was the
+ * first. But using bson_find() this way has the potential of
+ * traversing through a document multiple times.
+ *
+ * Now, if we know the one key always comes after another, then we can
+ * use bson_cursor_next() to help us find it, without having to
+ * restart from the beginning. We do this by extracting the key name
+ * from the cursor, and comparing it to whatever we're searching for:
+ * @until printf
+ *
+ * Now the above is still picky about key order, but it's at least
+ * more flexible: we can put any number of keys between author and
+ * inline, and it will work. In most cases, that's good enough. In
+ * every other case, where we have no idea about key ordering,
+ * bson_find() is still there for us.
+ *
+ * Even better, the library itself provides a function that does
+ * something similar: it takes a cursor and a key name, and attempts
+ * to find the key past the cursor's current position. So if we
+ * already have the author, we can use this function to find the next
+ * inline key aswell:
+ * @until printf
+ *
+ * However, if we suspect that a key might come after the current
+ * position, but we're not sure, and still want to find the key with
+ * as little code as possible, we shall not despair! The
+ * bson_cursor_find() function does just that: it will try to find the
+ * key starting from the current position, and wrap over once if it
+ * can't.
+ *
+ * Lets see how it works! First, we find a key in the middle:
+ * @until bson_find
+ *
+ * Now that we have a key in the middle, lets find a key after it:
+ * @until get_boolean
+ *
+ * And once we have that - and we're at the end of our BSON object -,
+ * lets try finding the author key aswell:
+ * @until get_string
+ *
+ * That works, just like that! To verify, we go ahead and print the
+ * results, which should be the same as it was in the previous
+ * examples:
+ *
+ * @until cursor_free
+ *
+ * @until printf
+ *
+ * One thing we did not explore yet, is bson_cursor_new(): this will
+ * create a new cursor, and point to to the very beginning of our BSON
+ * object, just before the first key. Thus, the first
+ * bson_cursor_next() done afterwards will yield the first key.
+ * @until bson_cursor_free
+ *
+ * Very well! But what if we want to see the title of the second page
+ * within the pages array? Unfortunately, that is a bit more work to
+ * accomplish: we'll need to extract the pages array from our
+ * document, and then extract its second element, and then we can find
+ * stuff in that:
+ * @until printf
+ *
+ * And that concludes our BSON traversing tutorial!
+ *
+ * @until }
+ */
diff --git a/docs/tutorial/tut_hl_client.h b/docs/tutorial/tut_hl_client.h
new file mode 100644
index 0000000..8b8e806
--- /dev/null
+++ b/docs/tutorial/tut_hl_client.h
@@ -0,0 +1,86 @@
+/** @page tut_hl_client A full-blown application
+ *
+ * As the next step of our tutorial, we will write a full blown
+ * application. While it does not solve any real-life problems, and
+ * what it does is entirely pointless, it nevertheless is a good
+ * example to showcase certain patterns one is likely to run into
+ * while developing with libmongo-client.
+ *
+ * @dontinclude tut_hl_client.c
+ * @until string.h
+ *
+ * Our first task is to add a handful of items to our test
+ * collection. We'll have two static keys, and one that's different
+ * for each key.
+ * @until gint i
+ *
+ * First, we'll build a base BSON object:
+ * @until bson_finish
+ *
+ * Then, we create a copy, append a counter element to the object,
+ * insert it, and do this a thousand times over.
+ * @until bson_free
+ * @until }
+ *
+ * This was pretty simple, wasn't it? And we even have error handling!
+ * Lets finish this function up, and move on.
+ *
+ * @until }
+ *
+ * Next up comes the interesting part: doing queries. We will use the
+ * @ref mongo_sync_cursor "cursor API" to iterate over all our
+ * results, hiding the gory details of database access behind its
+ * convenience layer.
+ *
+ * @until {
+ *
+ * We'll need a couple of things: a cursor, a query, and a string to
+ * store error messages in, if any.
+ *
+ * @until error
+ *
+ * Before we can query the database, we must build a query object:
+ * @until bson_finish
+ *
+ * Once that is done, we create a cursor, cleverly embedding the
+ * mongo_sync_cmd_query() call into the constructor:
+ * @until bson_free
+ *
+ * Again, we properly handle errors. It is very important to not just
+ * blindly assume things will work. While the library tries its best
+ * to handle invalid data gracefully, it's easy to get lost between
+ * the layers when one forgets to handle error cases at the
+ * appropriate level.
+ *
+ * But I digress, lets get back to our program!
+ *
+ * We have a nice little query cursor, it's time to loop through the
+ * database, extract the counter from the current BSON object, and
+ * move on:
+ * @until }
+ *
+ * At this point, we have the current document in the @a b variable,
+ * handled the error case, and as such, we're ready to dig deep into
+ * the BSON object!
+ * @until printf
+ *
+ * And once we're done working with the BSON object, we free the
+ * cursor, and the object, and continue the loop.
+ * @until }
+ *
+ * And in the end, we emit a newline, and free the cursor to wrap up
+ * our query routine.
+ * @until }
+ *
+ * All that is left now, is the glue that holds this together, and
+ * connects to MongoDB:
+ * @until }
+ * @until }
+ *
+ * I believe that does not need any further explanation.
+ *
+ * As an exercise, one can add another feature: dropping the temporary
+ * collection on error. Or perhaps, count the number of documents
+ * returned, and see if and how the count changes between subsequent
+ * runs of the test program.
+ */
diff --git a/docs/tutorial/tut_json2bson.h b/docs/tutorial/tut_json2bson.h
new file mode 100644
index 0000000..f263234
--- /dev/null
+++ b/docs/tutorial/tut_json2bson.h
@@ -0,0 +1,97 @@
+/** @page tut_json2bson JSON to BSON converter
+ *
+ * Now that we have a basic grasp of the library, we'll write a
+ * solution to a real life problem: converting JSON to BSON.
+ *
+ * Our program will expect correctly formatted JSON, in condensed
+ * one-line format, and will output a BSON document for each line of
+ * JSON received.
+ *
+ * @dontinclude tut_json2bson.c
+ * @until glib.h
+ *
+ * First, we forward declare the json_to_bson() function, because
+ * we'll recursively use it later on:
+ * @until json_to_bson
+ *
+ * Next, we create the heart of the program, a function that takes a
+ * BSON object, a value and a key, and appends the key-value pair to
+ * the bson object, with the correct type.
+ * @until {
+ *
+ * We do this by checking the JSON object's type, and acting up on it:
+ * @until switch
+ * @until {
+ *
+ * The boolean, double, integer and string types are easy: we just use
+ * the appropriate bson_append_*() function:
+ * @until break
+ * @until break
+ * @until break
+ * @until break
+ *
+ * Converting a JSON object to BSON is a bit more complicated, yet,
+ * straightforward nevertheless:
+ * @until }
+ *
+ * This is one of the reasons we needed to forward-declare
+ * json_to_bson(): we're using it to turn the JSON value into BSON,
+ * and append it as a subdocument.
+ *
+ * Next up: arrays! This is even trickier than sub-documents, as we
+ * need to iterate over the elements, and append each
+ * individually. But, trickier as it may be, it's still
+ * straightforward;
+ * @until }
+ * @until }
+ *
+ * Anything else, we ignore:
+ * @until break
+ *
+ * @until }
+ *
+ * @until }
+ *
+ * And to bind this together with JSON-C's API, we need two more
+ * functions. The first one will simply iterate over a JSON object,
+ * and call the function we wrote above:
+ * @until }
+ * @until }
+ *
+ * The next one is another wrapper around this former: it creates a
+ * BSON document, calls the foreach method, then finishes the BSON
+ * object and we're done:
+ * @until }
+ *
+ * We're almost done! All that is left is writing our program's entry
+ * point: something that will read the input, turn it into BSON, and
+ * write it out:
+ *
+ * @until json_tokener
+ *
+ * We do some setting up, creating a new IO channel, and a JSON
+ * tokenizer:
+ * @until tokener =
+ *
+ * Then, until we have something to read...
+ * @until {
+ * @until bson
+ *
+ * We reset the tokenizer before parsing another line, then parse the
+ * JSON we received:
+ * @until }
+ *
+ * If we received something other than a JSON object, we can't turn
+ * that into BSON, so we write an error to STDERR, and skip this line:
+ * @until }
+ *
+ * Otherwise, we turn it into BSON, and write it to STDOUT:
+ * @until bson_free
+ *
+ * @until }
+ *
+ * And that was our program, a very simple application that turns each
+ * line of JSON into BSON.
+ *
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync.h b/docs/tutorial/tut_mongo_sync.h
new file mode 100644
index 0000000..bc86a7e
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync.h
@@ -0,0 +1,16 @@
+/** @page tut_mongo_sync Working with the Mongo Sync API
+ *
+ * In this section we'll be going over various parts of the
+ * synchronous API provided by libmongo-client. From connecting to a
+ * single host, through replica sets to performing various more
+ * complex operations.
+ *
+ * Contents:
+ * - @subpage tut_mongo_sync_connect
+ * - @subpage tut_mongo_sync_insert
+ * - @subpage tut_mongo_sync_query
+ * - @subpage tut_mongo_sync_query_complex
+ * - @subpage tut_mongo_sync_cmd_create
+ * - @subpage tut_mongo_sync_cmd_index_create
+ * - @subpage tut_mongo_sync_cmd_custom
+ */
diff --git a/docs/tutorial/tut_mongo_sync_cmd_create.h b/docs/tutorial/tut_mongo_sync_cmd_create.h
new file mode 100644
index 0000000..f05940d
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_cmd_create.h
@@ -0,0 +1,53 @@
+/** @page tut_mongo_sync_cmd_create Creating collections
+ *
+ * In this simple example we'll learn how to explicitly create
+ * collections with the library, be those normal collections, capped
+ * ones or simply preallocated.
+ *
+ * Our application will attempt to create a normal collection, a
+ * capped one, a capped one that's also capped on the number of
+ * entries, and a pre-allocated (but uncapped) collection.
+ *
+ * It will print these properties of the collections aswell, so that
+ * we can verify that the creation did indeed work.
+ *
+ * @dontinclude tut_mongo_sync_cmd_create.c
+ * @until stdio.h
+ *
+ * First of all, we need a function that prints the collection
+ * properties. Because we're lazy, it will take a BSON object, as
+ * returned by mongo_sync_cmd_exists().
+ *
+ * The output of said command is a BSON object that has a @a name
+ * field, which is the full name of the collection, the database part
+ * included; and an @a options subdocument, which lists various
+ * options specified during creating, such as cappedness, size and
+ * maximum number of elements.
+ *
+ * Our very simple function will extract all these and print what's
+ * appropriate. It will also free the BSON object it was given, so
+ * that we don't leak memory.
+ * @until printf ("\n")
+ * @until }
+ *
+ * With that done, lets get down to business, and create the
+ * collections, after connecting to the server, of course.
+ * @until }
+ *
+ * First we create a completely normal collection, with the default
+ * settings:
+ * @until print_coll_info
+ *
+ * Then a capped collection:
+ * @until print_coll_info
+ *
+ * Followed by another capped collection, one that is also capped by
+ * the number of elements, not only by size:
+ * @until print_coll_info
+ *
+ * And finally, we create a pre-allocated collection:
+ * @until print_coll_info
+ *
+ * And that's about it, really.
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_cmd_custom.h b/docs/tutorial/tut_mongo_sync_cmd_custom.h
new file mode 100644
index 0000000..0b224b2
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_cmd_custom.h
@@ -0,0 +1,64 @@
+/** @page tut_mongo_sync_cmd_custom Running custom commands
+ *
+ * Sometimes it is necessary to run custom commands against a
+ * database, commands for which the library does not provide a
+ * convenience wrapper for. In this tutorial, we will explore how to
+ * run server-side evaluations, using the @a $eval command.
+ *
+ * @dontinclude tut_mongo_sync_cmd_custom.c
+ * @until stdlib.h
+ *
+ * @until eval
+ *
+ * First, we connect to the database, and create a BSON object that
+ * will hold our command, one that creates a function server side,
+ * that takes one argument, and returns the argument plus 4.2. The
+ * BSON object will also set up the arguments passed to this function,
+ * which, in our case, will be the number @a 1.
+ *
+ * @line conn =
+ * @until }
+ *
+ * @line eval =
+ * @until bson_finish
+ *
+ * Once we have the connection and the query established, it is time
+ * to send the command:
+ *
+ * @line p =
+ * @until }
+ *
+ * We then create a cursor from the returned packet, and iterate over
+ * it (in case there are multiple documents returned - which will not
+ * be the case here):
+ *
+ * @line cursor =
+ * @until }
+ *
+ * @until gdouble
+ *
+ * We want to retrieve each document, and find the @a retval key in
+ * them, because that's where @a $eval returns the results to us.
+ *
+ * @line result =
+ * @until }
+ * @until }
+ *
+ * At this point, we have successfully extracted the data, so we can
+ * free up the BSON and cursor objects.
+ *
+ * @line bson_cursor_free
+ * @until bson_free
+ *
+ * And finally, print the result:
+ *
+ * @until printf
+ *
+ * @until }
+ *
+ * And that's it! We clean up, disconnect, and that's all there is to
+ * running custom commands!
+ *
+ * @line mongo_sync_cursor_free
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_cmd_index_create.h b/docs/tutorial/tut_mongo_sync_cmd_index_create.h
new file mode 100644
index 0000000..22842e0
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_cmd_index_create.h
@@ -0,0 +1,66 @@
+/** @page tut_mongo_sync_cmd_index_create Creating indexes
+ *
+ * This example will show how to properly create indexes, how to
+ * verify its success, and will also give hints on how to prepare the
+ * BSON used to create the index.
+ *
+ * @dontinclude tut_mongo_sync_cmd_index_create.c
+ * @until stdio.h
+ *
+ * We will be creating and verifying multiple indexes, so lets create
+ * a function that takes a connection, a prepared index, and does the
+ * create and verify magic.
+ *
+ * @line static void
+ * @until }
+ * @until }
+ *
+ * This will create the index, and if it succeeds, write that to
+ * stdout. If it fails, it will try to query the last error, and print
+ * that to stderr.
+ *
+ * All we have to do past this point, is to build a few index
+ * specifications in BSON, and see what happens:
+ *
+ * @line int
+ * @until bson
+ *
+ * @line invalid
+ * @until bson_finish
+ *
+ * The first index spec we create will have a single index field, @a
+ * name, where we set the value to an empty string. However - as we
+ * will soon see - this is not a valid specification, as MongoDB does
+ * not accept string-typed fields in the index spec.
+ *
+ * @line index
+ * @until bson_finish
+ *
+ * Armed with the knowledge that strings are not going to work, we
+ * turn to our trusty old integers. Integers (32-bit integers at that,
+ * there really is no need to use a 64-bit value here) are the best
+ * fit for the type of an index field, because one can tell MongoDB
+ * the sort order (with negative or positive numbers) with them easily.
+ *
+ * @line conn =
+ * @until }
+ *
+ * We now have two index specs in BSON, and an established connection,
+ * lets see what happens!
+ *
+ * @line create_and_verify
+ * @until conn, index
+ *
+ * The first will - as explained above - fail, the second will
+ * succeed.
+ *
+ * And that is all it takes to create simple indexes! We now free up
+ * our BSON objects and disconnect, and the tutorial program is all
+ * done and finished.
+ *
+ * @line bson_free
+ * @until disconnect
+ *
+ * @line return
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_connect.h b/docs/tutorial/tut_mongo_sync_connect.h
new file mode 100644
index 0000000..1fb8b4a
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_connect.h
@@ -0,0 +1,49 @@
+/** @page tut_mongo_sync_connect Connecting to MongoDB
+ *
+ * The next step in our journey is to connect to MongoDB: to a single
+ * server and to a replicaset alike.
+ *
+ * Our first task is to connect to a MongoDB server, listening
+ * on localhost's 27017 port. And we don't care whether it is a master
+ * or a secondary, so we set the slave_ok argument to TRUE:
+ *
+ * @dontinclude tut_mongo_sync.c
+ * @skip void
+ * @until mongo_sync_disconnect
+ * @until }
+ *
+ * It's fairly straightforward: error handling is done using errno
+ * values, because that saves us from inventing our own statuses:
+ * POSIX provides us with plenty, and the C library uses errno
+ * extensively well. So does libmongo-client!
+ *
+ * Next up, is connecting to a replicaset:
+ *
+ * @until return;
+ * @until }
+ *
+ * Wait a minute! Does this look familiar? Isn't it @b exactly the
+ * same as in the former example (apart from the host name)? It sure
+ * is! There really is no difference between connecting to a single
+ * server and to a replica set when using the Sync API. It hides all
+ * the boring things from the user.
+ *
+ * However, if the server is a replicaset, we can add seeds: seeds are
+ * hosts that are not listed in the replicaset's public config
+ * (meaning they're hidden), but we still want to be able to use them,
+ * if so need be.
+ *
+ * It's not neccessary to add seeds, if the replica set itself
+ * advertises secondaries: the library will discover those, and
+ * reconnect to them, if automatic reconnection is turned on. Lets
+ * just do that!
+ *
+ * @until }
+ *
+ * Then we can add the seeds:
+ * @until }
+ * @until }
+ *
+ * And that's about it! We wrap up our function, and we're done!
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_insert.h b/docs/tutorial/tut_mongo_sync_insert.h
new file mode 100644
index 0000000..aaf0754
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_insert.h
@@ -0,0 +1,46 @@
+/** @page tut_mongo_sync_insert Inserting documents into MongoDB
+ *
+ * Now that we know how to connect, it is time to take another step
+ * forward, and put something into our database. We already learned
+ * how to build BSON objects in @ref tut_bson_build, so lets put that
+ * knowledge together, and insert a document!
+ *
+ * @dontinclude tut_mongo_sync.c
+ * @skip tut_sync_connect_replica
+ * @skip }
+ * @skip void
+ * @until {
+ *
+ * First, we define a couple of variables, a connection, and three documents:
+ *
+ * @until bson
+ *
+ * Then we do our routine connect:
+ * @until }
+ *
+ * And then build a BSON object, as we've learned earlier:
+ * @until bson_finish
+ *
+ * Now we have a connection, and we have a document, it's time to get
+ * dirty, and insert:
+ *
+ * @until }
+ *
+ * One might wonder what that @c NULL is at the end of
+ * mongo_sync_cmd_insert()'s argument list: it's the @a sentinel. The
+ * value that marks the end of the documents we want to insert. It is
+ * needed, because the insert command can take any number of
+ * documents, and it will try to insert them in bulk.
+ *
+ * Lets try that, and build two more documents:
+ * @until bson_finish (doc3)
+ *
+ * Then we insert the two new documents into the same collection, at
+ * the same time:
+ * @until }
+ *
+ * And we're done! It's that straightforward. All we have left is
+ * cleaning up!
+ *
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_query.h b/docs/tutorial/tut_mongo_sync_query.h
new file mode 100644
index 0000000..ebed5a1
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_query.h
@@ -0,0 +1,67 @@
+/** @page tut_mongo_sync_query Querying documents
+ *
+ * We can connect, insert, and we still vaguely remember how to build
+ * BSON objects: how about we go out and query the database this time?
+ *
+ * @dontinclude tut_mongo_sync.c
+ * @skip tut_sync_insert
+ * @skip }
+ * @skip void
+ * @until {
+ *
+ * First, we define a couple of variables: a connection, a packet, a
+ * cursor, a BSON object and a counter:
+ *
+ * @until gint i
+ *
+ * We'll use the packet as an intermediate step between querying and
+ * making a cursor. We'll see why later. The query will be used to
+ * limit the documents queried, and the counter is just for pretty
+ * printing.
+ *
+ * Then we do our routine connect:
+ * @until }
+ *
+ * And then build a BSON object, an empty one, because an empty query
+ * means we're interested in all of the documents!
+ * @until bson_finish
+ *
+ * Now we have a connection, and we have a query, lets tell MongoDB
+ * what we want:
+ *
+ * @until bson_free
+ *
+ * The first two parameters are obvious. The third is a set of flags -
+ * but we don't use any right now. Then comes the number of documents
+ * to skip, and the number of documents to return, followed by a
+ * query, and an optional field selector, which we just left empty
+ * (meaning we want all fields returned).
+ *
+ * There's more than one way to figure out the data returned by a
+ * query: we can either use the returned packet as-is, and extract
+ * data from it using the low-level mongo_wire family of functions. Or
+ * we can make a cursor out of this packet, and iterate over the
+ * elements:
+ *
+ * @until }
+ *
+ * @until }
+ *
+ * The first thing we do inside of the loop is to get the data from
+ * the cursor - or bail out with an error if we can't.
+ *
+ * @until printf
+ *
+ * Then we proceed to make a BSON cursor, and print all the keys that
+ * belong to the document.
+ *
+ * Once that's done, we free the resources we used, and continue along
+ * the loop, until our cursor signals the end of the query.
+ *
+ * @until printf
+ *
+ * @until }
+ *
+ * Then we clean up and go home:
+ * @until }
+ */
diff --git a/docs/tutorial/tut_mongo_sync_query_complex.h b/docs/tutorial/tut_mongo_sync_query_complex.h
new file mode 100644
index 0000000..145ab0e
--- /dev/null
+++ b/docs/tutorial/tut_mongo_sync_query_complex.h
@@ -0,0 +1,43 @@
+/** @page tut_mongo_sync_query_complex Querying documents, part two
+ *
+ * We learned how to make simple queries in the previous section,
+ * we'll be brave and do something much more advanced this time: we'll
+ * limit the query to documents that have their @c "yes?" field set to
+ * @a FALSE, and sort the results by the @c "n" field, in ascending
+ * order.
+ *
+ * @dontinclude tut_mongo_sync.c
+ * @skip tut_sync_query_simple
+ * @skip }
+ * @skip void
+ * @until {
+ *
+ * @until gint i
+ *
+ * @until }
+ *
+ * After our routine connect, we build the query and select BSON
+ * objects:
+ *
+ * @until bson_finish (select)
+ *
+ * Then we launch the query:
+ * @until bson_free (select)
+ *
+ * And make a cursor, just like last time:
+ * @until }
+ *
+ * And that's pretty much the bulk of what we wanted to do: we just
+ * constructed our query and select BSON objects appropriately, and
+ * mongo_sync_cmd_query() does the rest.
+ *
+ * But just to make sure our results are sane, we iterate over the
+ * returned documents, and print the fields we're interested in:
+ *
+ * @until i++
+ * @until }
+ *
+ * And when that is done, all that is left, is to clean up after
+ * ourselves:
+ * @until }
+ */
diff --git a/docs/tutorial/tutorial.h b/docs/tutorial/tutorial.h
new file mode 100644
index 0000000..e136071
--- /dev/null
+++ b/docs/tutorial/tutorial.h
@@ -0,0 +1,34 @@
+/** @page tutorial Tutorial
+ *
+ * These pages will attempt to guide one through the libmongo-client
+ * library, starting from the basic BSON building blocks, through the
+ * low level wire protocol API, until the highest level synchronous
+ * API.
+ *
+ * The documentation assumes a reasonable amount of C knowledge, and
+ * basic familiarity with MongoDB concepts.
+ *
+ * The example programs can be found in the @c docs/tut/examples
+ * directory in the source tree, along with a Makefile. Would one want
+ * to compile the examples, or modified versions of them by hand, then
+ * the following command should work:
+ *
+ * @verbatim
+$ cc $(pkg-config --cflags libmongo-client) tut_bson_build.c $(pkg-config --libs libmongo-client) -o tut_bson_build
+@endverbatim
+ *
+ * Contents:
+ * - @subpage tut_bson
+ * - @ref tut_bson_build
+ * - @ref tut_bson_traverse
+ * - @subpage tut_mongo_sync
+ * - @ref tut_mongo_sync_connect
+ * - @ref tut_mongo_sync_insert
+ * - @ref tut_mongo_sync_query
+ * - @ref tut_mongo_sync_query_complex
+ * - @ref tut_mongo_sync_cmd_create
+ * - @ref tut_mongo_sync_cmd_index_create
+ * - @ref tut_mongo_sync_cmd_custom
+ * - @subpage tut_hl_client
+ * - @subpage tut_json2bson
+ */