[tracker/wip/carlosg/doc-improvements: 4/6] docs: Update and modernize code examples




commit 605dfcd482395561d666089ad7dbb82e3a1fc822
Author: Carlos Garnacho <carlosg gnome org>
Date:   Wed Sep 15 23:46:55 2021 +0200

    docs: Update and modernize code examples
    
    Update these to contain better real-world examples, with more
    modern code practices. As a result some examples on TrackerEndpoint
    and TrackerNotifier were added, while the one on blank nodes was
    simply dropped.
    
    Also improve the wording around those examples, like avoiding to
    mention all existing API like a 8yo enumerating his xmas gift list.
    
    Fixes: https://gitlab.gnome.org/GNOME/tracker/-/issues/157

 docs/reference/libtracker-sparql/examples.md.in    | 114 ++++++++++-----------
 .../examples/connection-example.c                  |  60 +++++++++++
 .../libtracker-sparql/examples/endpoint-example.c  |  37 +++++++
 .../libtracker-sparql/examples/meson.build         |  19 ++--
 .../libtracker-sparql/examples/notifier-example.c  |  48 +++++++++
 .../examples/private-store-example.c               |  41 ++++++++
 .../libtracker-sparql/examples/readonly-example.c  |  92 -----------------
 .../libtracker-sparql/examples/writeonly-example.c |  47 ---------
 .../examples/writeonly-with-blank-nodes-example.c  |  61 -----------
 9 files changed, 251 insertions(+), 268 deletions(-)
---
diff --git a/docs/reference/libtracker-sparql/examples.md.in b/docs/reference/libtracker-sparql/examples.md.in
index b5cc86f62..6a60320a7 100644
--- a/docs/reference/libtracker-sparql/examples.md.in
+++ b/docs/reference/libtracker-sparql/examples.md.in
@@ -8,22 +8,16 @@ short-description: Examples
 This chapters shows some real examples of usage of the Tracker
 SPARQL Library.
 
-## Querying the Store
+## Querying a remote endpoint
 
-First, a [](TrackerSparqlConnection) object must be acquired
-with [](tracker_sparql_connection_new), [](tracker_sparql_connection_bus_new)
-or [](tracker_sparql_connection_remote_new).
+All SPARQL queries happen on a [](TrackerSparqlConnection), often these
+connections represent a remote endpoints maintained by another process or
+server.
 
-Then, a query can be launched either synchronously ([](tracker_sparql_connection_query))
-or asynchronously ([](tracker_sparql_connection_query_async)). If launched
-asynchronously, the results of the query can be obtained with
-[](tracker_sparql_connection_query_finish).
-
-If the query was successful, a [](TrackerSparqlCursor)
-will be available. You can now iterate the results of the query both
-synchronously (with [](tracker_sparql_cursor_next)) or asynchronously
-(with [](tracker_sparql_cursor_next_async) and
-[](tracker_sparql_cursor_next_finish)).
+This example demonstrates the use of these connections on a remote
+endpoint. Concretely creating a D-Bus [](TrackerSparqlConnection),
+creating a prepared statement from a SPARQL query string, executing
+the query, and obtaining the query results from the cursor.
 
 The [](tracker_sparql_connection_query_statement) function can be used
 to obtain a [](TrackerSparqlStatement) object holding a prepared SPARQL
@@ -34,70 +28,66 @@ arbitrary values before query execution with
 This allows parsing the query string only once and to execute it multiple
 times with different parameters with potentially significant performance gains.
 
+Multiple functions offer asynchronous variants, so the application
+main loop is not blocked while these operations are executed.
+
 Once you end up with the query, remember to call [](tracker_sparql_cursor_close).
 The same applies to [](tracker_sparql_connection_close) when no longer needed.
 
-The following program shows how Read-Only queries can be done to the store in a
-synchronous way:
-
 ```c
-{{examples/readonly-example.c}}
+{{examples/connection-example.c}}
 ```
 
-## Updating the store
+## Creating a private database
 
-In order to perform updates in the store, a new writable
-[](TrackerSparqlConnection) object must be acquired with
-[](tracker_sparql_connection_new).
+Applications may create private stores via the [](tracker_sparql_connection_new)
+constructor.
 
-Once a proper connection object has been acquired, the update can
-be launched either synchronously ([](tracker_sparql_connection_update))
-or asynchronously ([](tracker_sparql_connection_update_async)).
-If launched asynchronously, the result of the operation can be obtained with
-[](tracker_sparql_connection_update_finish).
+This example demonstrates the creation of a private store, for simplicity the
+example uses the builtin Nepomuk ontology, but the data structures may be defined
+by the application, see the documentation on
+[defining ontologies](defining-ontologies.md) for more information about this.
+
+The example also demonstrates the use of [](TrackerResource) and [](TrackerBatch)
+for insertion of RDF data. It is also possible the direct use of SPARQL update
+strings via [](tracker_sparql_connection_update).
+
+Multiple functions offer asynchronous variants, so the application
+main loop is not blocked while these operations are executed.
 
 Once you no longer need the connection, remember to call
 [](tracker_sparql_connection_close) on the [](TrackerSparqlConnection).
 
-The following program shows how a synchronous update can be done to the store:
+```c
+{{examples/private-store-example.c}}
+```
+
+## Creating a SPARQL endpoint
+
+For some applications and services, it might be desirable to export a
+SPARQL store as an endpoint. Making it possible for other applications to
+query the data they hold.
+
+This example demonstrates the use of [](TrackerEndpoint) subclasses,
+concretely the creation of a D-Bus endpoint, that other applications
+may query e.g. through a connection created with
+[](tracker_sparql_connection_bus_new).
 
 ```c
-{{examples/writeonly-example.c}}
+{{examples/endpoint-example.c}}
 ```
 
-## Updating the store with blank nodes
-
-The majority of the work here is already described in the
-[previous example](#updating-the-store) where we talk about how to write the store.
-
-The difference with this example is that sometimes you want to
-insert data and have the URNs returned which were created to
-avoid re-querying for them. This is done using
-the [](tracker_sparql_connection_update_blank) function (or asynchronously with
-[](tracker_sparql_connection_update_blank_async)).
-If launched asynchronously, the result of the operation can be obtained with
-[](tracker_sparql_connection_update_blank_finish)]
-
-The `_:foo` in the example is how a blank node is
-represented in SPARQL. The `foo` part is used to generate the
-unique ID that is used for the new URN. It is also used in the
-`GVariant` that is returned. In the example below, we are creating
-a new blank node called `foo` for every class that exists.
-
-The format of the `GVariant` (in D-Bus terms) is `aaa{ss}` (an
-array of an array of dictionaries). This is rather complex but
-for a good reason. The first array represents each INSERT that
-may exist in the SPARQL. The second array represents each new
-node for a given WHERE clause (the example below illustrates
-this), you need this to differentiate between two INSERT
-statments like the one below in the same SPARQL sent to the
-store. Last, we have a final array to represent each new node's
-name (in this case `foo`) and the actual URN which was
-created. For most updates the first two outer arrays will only
-have one item in them.
-
-The following program shows how a synchronous blank node update can be done to the store:
+## Receiving notification on changes
+
+As an additional feature over SPARQL endpoints, Tracker allows for
+users of private and D-Bus SPARQL connections to receive notifications
+on changes of certain RDF classes (Those with the
+[nrl:notify](nrl-ontology.md#nrl:notify) property, like
+[nmm:MusicPiece](nmm-ontology.md#nmm:MusicPiece)).
+
+This example demonstrates the use of [](TrackerNotifier) to receive
+notifications on database updates.
 
 ```c
-{{examples/writeonly-with-blank-nodes-example.c}}
+{{examples/notifier-example.c}}
 ```
diff --git a/docs/reference/libtracker-sparql/examples/connection-example.c 
b/docs/reference/libtracker-sparql/examples/connection-example.c
new file mode 100644
index 000000000..664d004ac
--- /dev/null
+++ b/docs/reference/libtracker-sparql/examples/connection-example.c
@@ -0,0 +1,60 @@
+#include <libtracker-sparql/tracker-sparql.h>
+
+#define REMOTE_NAME "org.freedesktop.Tracker3.Miner.Files"
+
+int main (int argc, const char **argv)
+{
+  g_autoptr (GError) error = NULL;
+  g_autoptr (TrackerSparqlConnection) connection = NULL;
+  g_autoptr (TrackerSparqlCursor) cursor = NULL;
+  g_autoptr (TrackerSparqlStatement) stmt = NULL;
+  const char *query = "SELECT nie:url(?u) WHERE { ?u a nfo:FileDataObject ; nfo:fileName ~name }";
+  const char *name = NULL;
+  int i = 0;
+
+  connection = tracker_sparql_connection_bus_new (REMOTE_NAME, NULL, NULL, &error);
+  if (!connection) {
+    g_printerr ("Couldn't obtain a connection to the Tracker store: %s",
+                error ? error->message : "unknown error");
+    return 1;
+  }
+
+  /* Create a prepared statement */
+  stmt = tracker_sparql_connection_query_statement (connection,
+                                                    query,
+                                                    NULL,
+                                                    &error);
+
+  if (!stmt) {
+    g_printerr ("Couldn't create a prepared statement: '%s'",
+                error->message);
+    return 1;
+  }
+
+  /* Bind a value to the query variables */
+  name = argv[1] ? argv[1] : "";
+  tracker_sparql_statement_bind_string (stmt, "name", name);
+
+  /* Executes the SPARQL query with the currently bound values and get new cursor */
+  cursor = tracker_sparql_statement_execute (stmt, NULL, &error);
+  if (!cursor) {
+    g_printerr ("Couldn't execute query: '%s'",
+                error->message);
+    return 1;
+  }
+
+  /* Iterate synchronously the results */
+  while (tracker_sparql_cursor_next (cursor, NULL, &error)) {
+    g_print ("Result [%d]: %s\n",
+             i++,
+             tracker_sparql_cursor_get_string (cursor, 0, NULL));
+  }
+
+  g_print ("A total of '%d' results were found\n", i);
+
+  tracker_sparql_cursor_close (cursor);
+
+  tracker_sparql_connection_close (connection);
+
+  return 0;
+}
diff --git a/docs/reference/libtracker-sparql/examples/endpoint-example.c 
b/docs/reference/libtracker-sparql/examples/endpoint-example.c
new file mode 100644
index 000000000..ba793b60a
--- /dev/null
+++ b/docs/reference/libtracker-sparql/examples/endpoint-example.c
@@ -0,0 +1,37 @@
+#include <libtracker-sparql/tracker-sparql.h>
+
+int main (int argc, const char **argv)
+{
+  g_autoptr (GError) error = NULL;
+  g_autoptr (TrackerSparqlConnection) connection = NULL;
+  g_autoptr (GFile) ontology = NULL;
+  g_autoptr (GMainLoop) main_loop = NULL;
+
+  /* Create a SPARQL store */
+  ontology = tracker_sparql_get_ontology_nepomuk ();
+  connection = tracker_sparql_connection_new (TRACKER_SPARQL_CONNECTION_FLAGS_NONE,
+                                             NULL, /* Database location, NULL creates it in-memory */
+                                             ontology, /* Ontology location */
+                                             NULL,
+                                             &error);
+  if (connection) {
+    g_printerr ("Couldn't create a Tracker store: %s",
+                error->message);
+    return 1;
+  }
+
+  /* Make the connection available via D-Bus, other applications would be
+   * able to make connections to this application's bus name
+   */
+  endpoint = tracker_endpoint_dbus_new (connection, NULL, NULL, NULL, &error);
+  if (!endpoint) {
+    g_printerr ("Couldn't create D-Bus endpoint: %s",
+                error->message);
+    return 1;
+  }
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (main_loop);
+
+  return 0;
+}
diff --git a/docs/reference/libtracker-sparql/examples/meson.build 
b/docs/reference/libtracker-sparql/examples/meson.build
index 1cb1d9f3f..4f7a1f2e4 100644
--- a/docs/reference/libtracker-sparql/examples/meson.build
+++ b/docs/reference/libtracker-sparql/examples/meson.build
@@ -1,20 +1,27 @@
 executable(
-  'readonly-example',
-  'readonly-example.c',
+  'connection-example',
+  'connection-example.c',
   dependencies: tracker_sparql_dep,
   build_by_default: true
 )
 
 executable(
-  'writeonly-example',
-  'writeonly-example.c',
+  'private-store-example',
+  'private-store-example.c',
   dependencies: tracker_sparql_dep,
   build_by_default: true
 )
 
 executable(
-  'writeonly-with-blank-nodes-example',
-  'writeonly-with-blank-nodes-example.c',
+  'endpoint-example',
+  'endpoint-example.c',
+  dependencies: tracker_sparql_dep,
+  build_by_default: true
+)
+
+executable(
+  'notifier-example',
+  'notifier-example.c',
   dependencies: tracker_sparql_dep,
   build_by_default: true
 )
diff --git a/docs/reference/libtracker-sparql/examples/notifier-example.c 
b/docs/reference/libtracker-sparql/examples/notifier-example.c
new file mode 100644
index 000000000..7e6fa3d01
--- /dev/null
+++ b/docs/reference/libtracker-sparql/examples/notifier-example.c
@@ -0,0 +1,48 @@
+#include <libtracker-sparql/tracker-sparql.h>
+
+#define REMOTE_NAME "org.freedesktop.Tracker3.Miner.Files"
+
+void on_events (TrackerNotifier *notifier,
+                const char      *service,
+                const char      *graph,
+                GPtrArray       *events,
+                gpointer         user_data)
+{
+  int i;
+
+  for (i = 0; i < events->len; i++) {
+    TrackerNotifierEvent *event = g_ptr_array_index (events, i);
+
+    g_print ("Event %d on %s\n",
+             tracker_notifier_event_get_event_type (event),
+             tracker_notifier_event_get_urn (event));
+  }
+}
+
+int main (int   argc,
+          char *argv[])
+{
+  g_autoptr (GError) error = NULL;
+  g_autoptr (TrackerSparqlConnection) connection = NULL;
+  g_autoptr (TrackerNotifier) notifier = NULL;
+  g_autoptr (GMainLoop) main_loop = NULL;
+
+  /* Create connection to remote service */
+  connection = tracker_sparql_connection_bus_new (REMOTE_NAME, NULL, NULL, &error);
+  if (!connection) {
+    g_printerr ("Couldn't obtain a connection to the Tracker store: %s",
+                error ? error->message : "unknown error");
+    return 1;
+  }
+
+  /* Create notifier, and connect to its events signal */
+  notifier = tracker_sparql_connection_create_notifier (connection);
+  g_signal_connect (notifier, "events", G_CALLBACK (on_events), NULL);
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (main_loop);
+
+  tracker_sparql_connection_close (connection);
+
+  return 0;
+}
diff --git a/docs/reference/libtracker-sparql/examples/private-store-example.c 
b/docs/reference/libtracker-sparql/examples/private-store-example.c
new file mode 100644
index 000000000..8451503ac
--- /dev/null
+++ b/docs/reference/libtracker-sparql/examples/private-store-example.c
@@ -0,0 +1,41 @@
+#include <libtracker-sparql/tracker-sparql.h>
+
+int main (int argc, const char **argv)
+{
+  g_autoptr (GError) error = NULL;
+  g_autoptr (TrackerSparqlConnection) connection = NULL;
+  g_autoptr (TrackerResource) resource = NULL;
+  g_autoptr (GFile) ontology = NULL;
+
+  /* Create a private SPARQL store */
+  ontology = tracker_sparql_get_ontology_nepomuk ();
+  connection = tracker_sparql_connection_new (TRACKER_SPARQL_CONNECTION_FLAGS_NONE,
+                                             NULL, /* Database location, NULL creates it in-memory */
+                                             ontology, /* Ontology location */
+                                             NULL,
+                                             &error);
+  if (connection) {
+    g_printerr ("Couldn't create a Tracker store: %s",
+                error->message);
+    return 1;
+  }
+
+  /* Create a resource containing RDF data */
+  resource = tracker_resource_new (NULL);
+  tracker_resource_set_uri (resource, "rdf:type", "nmm:MusicPiece");
+
+  /* Create a batch, and add the resource to it */
+  batch = tracker_sparql_connection_create_batch (connection);
+  tracker_batch_add_resource (batch, NULL, resource);
+
+  /* Execute the batch to insert the data */
+  if (!tracker_batch_execute (batch, NULL, &error)) {
+    g_printerr ("Couldn't insert batch of resources: %s",
+                error->message);
+    return 1;
+  }
+
+  tracker_sparql_connection_close (connection);
+
+  return 0;
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]