Examples
This document shows some real examples of usage of the TinySPARQL library.
Querying a remote endpoint
All SPARQL queries happen through a TrackerSparqlConnection
, often
these connections represent a remote endpoints maintained by another process or server.
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()
method can be used
to obtain a TrackerSparqlStatement
object holding a prepared SPARQL
query that can then be executed with tracker_sparql_statement_execute()
.
The query string can contain ~name
placeholders which can be replaced with
arbitrary values before query execution with
tracker_sparql_statement_bind_string()
and similar functions.
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.
In C:
#include <tinysparql.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;
}
In Python:
#!/usr/bin/python3
import gi, sys
from gi.repository import GLib, Gio, Tsparql
try:
connection = Tsparql.SparqlConnection.bus_new(
'org.freedesktop.Tracker3.Miner.Files',
None, None)
stmt = connection.query_statement (
'SELECT DISTINCT nie:url(?u) WHERE { ' +
' ?u a nfo:FileDataObject ; ' +
' nfo:fileName ~name ' +
'}', None)
stmt.bind_string('name', sys.argv[1])
cursor = stmt.execute()
i = 0;
while cursor.next():
i += 1
print('Result {0}: {1}'.format(i, cursor.get_string(0)[0]))
print('A total of {0} results were found\n'.format(i))
cursor.close()
connection.close()
except Exception as e:
print('Error: {0}'.format(e))
sys.exit(-1)
In Javascript:
#!/usr/bin/gjs
const { GLib, Gio, Tsparql } = imports.gi
try {
let connection = Tsparql.SparqlConnection.bus_new(
'org.freedesktop.Tracker3.Miner.Files',
null, null);
let stmt = connection.query_statement (
'SELECT DISTINCT nie:url(?u) WHERE { ' +
' ?u a nfo:FileDataObject ; ' +
' nfo:fileName ~name ' +
'}', null);
stmt.bind_string('name', ARGV[0]);
let cursor = stmt.execute(null);
let i = 0;
while (cursor.next(null)) {
i++;
print(`Result ${i}: ${cursor.get_string(0)[0]}`);
}
print(`A total of ${i} results were found`);
cursor.close();
connection.close();
} catch (e) {
printerr(`Error: ${e.message}`)
}
Creating a private database
Applications may create private RDF triple stores via the tracker_sparql_connection_new()
constructor.
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 creating custom ontologies for more information about this.
The example also demonstrates the use of TrackerResource
and TrackerBatch
for insertion of RDF data. It is also possible to use TrackerSparqlStatement
for
updates through the tracker_batch_add_statement()
methods, or plain SPARQL strings
through tracker_batch_add_sparql()
.
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()
.
In C:
#include <tinysparql.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;
}
In Python:
#!/usr/bin/python3
import gi, sys
from gi.repository import GLib, Gio, Tsparql
try:
connection = Tsparql.SparqlConnection.new(
Tsparql.SparqlConnectionFlags.NONE,
None, # Database location, None creates it in-memory
Tsparql.sparql_get_ontology_nepomuk(), # Ontology location
None)
# Create a resource containing RDF data
resource = Tsparql.Resource.new(None)
resource.set_uri('rdf:type', 'nmm:MusicPiece')
# Create a batch, and add the resource to it
batch = connection.create_batch()
batch.add_resource(None, resource)
# Execute the batch to insert the data
batch.execute()
connection.close()
except Exception as e:
print('Error: {0}'.format(e))
sys.exit(-1)
In Javascript:
#!/usr/bin/gjs
const { GLib, Gio, Tsparql } = imports.gi
try {
let connection = Tsparql.SparqlConnection.new(
Tsparql.SparqlConnectionFlags.NONE,
null, // Database location, None creates it in-memory
Tsparql.sparql_get_ontology_nepomuk(), // Ontology location
null);
// Create a resource containing RDF data
let resource = Tsparql.Resource.new(null)
resource.set_uri('rdf:type', 'nmm:MusicPiece')
// Create a batch, and add the resource to it
let batch = connection.create_batch()
batch.add_resource(null, resource)
// Execute the batch to insert the data
batch.execute(null)
connection.close();
} catch (e) {
printerr(`Error: ${e.message}`)
}
Creating a SPARQL endpoint
For some applications and services, it might be desirable to export a RDF triple 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()
.
In C:
#include <tinysparql.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;
}
In Python:
#!/usr/bin/python3
import gi, sys
from gi.repository import GLib, Gio, Tsparql
try:
connection = Tsparql.SparqlConnection.new(
Tsparql.SparqlConnectionFlags.NONE,
None, # Database location, None creates it in-memory
Tsparql.sparql_get_ontology_nepomuk(), # Ontology location
None)
bus = Gio.bus_get_sync(Gio.BusType.SESSION, None)
endpoint = Tsparql.EndpointDBus.new(
connection, bus, None, None)
loop = GLib.MainLoop.new(None, False)
loop.run()
connection.close()
except Exception as e:
print('Error: {0}'.format(e))
sys.exit(-1)
In Javascript:
#!/usr/bin/gjs
const { GLib, Gio, Tsparql } = imports.gi
try {
let connection = Tsparql.SparqlConnection.new(
Tsparql.SparqlConnectionFlags.NONE,
null, // Database location, None creates it in-memory
Tsparql.sparql_get_ontology_nepomuk(), // Ontology location
null);
let bus = Gio.bus_get_sync(Gio.BusType.SESSION, null)
let endpoint = Tsparql.EndpointDBus.new(
connection, bus, null, null);
let loop = GLib.MainLoop.new(null, false);
loop.run();
connection.close();
} catch (e) {
printerr(`Error: ${e.message}`)
}
Receiving notification on changes
As an additional feature over SPARQL endpoints, TinySPARQL allows for users of private and D-Bus SPARQL connections to receive notifications on changes of certain RDF classes (Those with the nrl:notify property, like nmm:MusicPiece).
This example demonstrates the use of TrackerNotifier
to receive
notifications on database updates.
In C:
#include <tinysparql.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;
}
In Python:
#!/usr/bin/python3
import gi, sys
from gi.repository import GLib, Gio, Tsparql
def callback(service, graph, events):
for event in events:
print('Event {0} on {1}\n'.format(
event.get_event_type(), event.get_urn()))
try:
connection = Tsparql.SparqlConnection.bus_new(
'org.freedesktop.Tracker3.Miner.Files',
None, None)
notifier = connection.create_notifier()
notifier.connect('events', callback)
loop = GLib.MainLoop.new(None, False)
loop.run()
connection.close()
except Exception as e:
print('Error: {0}'.format(e))
sys.exit(-1)
In Javascript:
#!/usr/bin/gjs
const { GLib, Gio, Tsparql } = imports.gi
try {
let connection = Tsparql.SparqlConnection.bus_new(
'org.freedesktop.Tracker3.Miner.Files',
null, null);
let notifier = connection.create_notifier();
notifier.connect('events', (service, graph, events) => {
for (let event in events)
print (`Event ${event.get_event_type()} on ${event.get_urn()}`);
});
let loop = GLib.MainLoop.new(null, false);
loop.run();
connection.close();
} catch (e) {
printerr(`Error: ${e.message}`)
}