[gnome-books/wip/carlosg/tracker3: 6/7] Port queries to Tracker3




commit 42f689c851706521092248a248e8dbe097873f07
Author: Carlos Garnacho <carlosg gnome org>
Date:   Sun Jan 17 17:03:14 2021 +0100

    Port queries to Tracker3
    
    Use new Tracker.SparqlConnection constructors, and rework the queries
    so that it:
    
    1) Observes the data layout in use in Tracker Miners 3.x
    2) Uses a private database for the data considered writeable:
       - collections
       - titles
    
    All queries happen on the local connection, optionally including data
    from tracker-miner-fs via SERVICE{} clauses, this is just not the case
    for collection queries, since collections are stored in the private
    books database.

 meson.build              |  4 +-
 src/application.js       |  8 +++-
 src/documents.js         |  2 +-
 src/main.js              |  3 +-
 src/query.js             | 99 ++++++++++++++++++++++++++++++++++++------------
 src/search.js            |  8 ++--
 src/trackerController.js |  4 +-
 src/trackerUtils.js      |  2 +-
 8 files changed, 92 insertions(+), 38 deletions(-)
---
diff --git a/meson.build b/meson.build
index afd97aa4..f608bfc1 100644
--- a/meson.build
+++ b/meson.build
@@ -50,7 +50,6 @@ endforeach
 add_project_arguments('-DHAVE_CONFIG_H', language: 'c')
 
 evince_req_version = '>= 3.13.3'
-tracker_req_version = '>= 0.17.3'
 
 gjs_dep = dependency('gjs-1.0', version: '>= 1.48.0')
 gjs_console = gjs_dep.get_pkgconfig_variable('gjs_console')
@@ -63,8 +62,7 @@ books_deps = [
   dependency('gnome-desktop-3.0'),
   dependency('gobject-introspection-1.0', version: '>= 1.31.6'),
   dependency('gtk+-3.0', version: '>= 3.22.15'),
-  dependency('tracker-control-2.0', version: tracker_req_version),
-  dependency('tracker-sparql-2.0', version: tracker_req_version),
+  dependency('tracker-sparql-3.0'),
   dependency('webkit2gtk-4.0', version: '>= 2.6.0'),
   cc.find_library('m')
 ]
diff --git a/src/application.js b/src/application.js
index a6ac6f0f..c3ebf933 100644
--- a/src/application.js
+++ b/src/application.js
@@ -175,9 +175,13 @@ var Application = new Lang.Class({
 
         // connect to tracker
         try {
-            connection = Tracker.SparqlConnection.get(null);
+            let cacheDir = GLib.build_filenamev([GLib.get_user_cache_dir(), 'org.gnome.Books', 'db']);
+            let nepomuk = Tracker.sparql_get_ontology_nepomuk();
+            connection = Tracker.SparqlConnection.new(Tracker.SparqlConnectionFlags.NONE,
+                                                      Gio.File.new_for_path(cacheDir),
+                                                      nepomuk, null);
         } catch (e) {
-            logError(e, 'Unable to connect to the tracker database');
+            logError(e, 'Unable to set up the tracker database');
             return;
         }
 
diff --git a/src/documents.js b/src/documents.js
index b6aea652..a2f15c6b 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -803,7 +803,7 @@ const DocCommon = new Lang.Class({
         let retval = '';
 
         if (this.collection)
-            retval = '{ ?urn nie:isPartOf <' + this.id + '> }';
+            retval = '{ ?urn nie:isLogicalPartOf <' + this.id + '> }';
 
         return retval;
     },
diff --git a/src/main.js b/src/main.js
index 57f62019..d6624940 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,8 +33,7 @@ pkg.require({ 'EvinceDocument': '3.0',
               'GLib': '2.0',
               'Gtk': '3.0',
               'GObject': '2.0',
-              'Tracker': '2.0',
-              'TrackerControl': '2.0',
+              'Tracker': '3.0',
               'WebKit2': '4.0' });
 
 const Application = imports.application;
diff --git a/src/query.js b/src/query.js
index ce7928cd..fa7c5ca1 100644
--- a/src/query.js
+++ b/src/query.js
@@ -94,9 +94,6 @@ var QueryBuilder = new Lang.Class({
                 part += this._buildOptional();
 
                 if ((flags & QueryFlags.UNFILTERED) == 0) {
-                    if (global)
-                        part += this._context.documentManager.getWhere();
-
                     part += this._buildFilterString(currentType, flags, ftsQuery.length > 0);
                 }
 
@@ -139,12 +136,25 @@ var QueryBuilder = new Lang.Class({
 
         // put all the clauses in an UNION
         whereSparql += whereParts.join(' UNION ');
+
         whereSparql += ' }';
 
         return whereSparql;
     },
 
     _buildQueryInternal: function(global, flags, offsetController, sortBy) {
+       let selectClauses =
+            '    (nie:isStoredAs(?urn) AS ?uri) ' +
+            '    (nfo:fileName(?urn) AS ?filename) ' +
+            '    (nie:mimeType(?urn) AS ?mimetype) ' +
+            '    (nie:title(?urn) AS ?title) ' +
+            '    (tracker:coalesce(nco:fullname(?creator), nco:fullname(?publisher), \'\') AS ?author) ' +
+            '    (nie:contentLastModified(?urn) AS ?mtime) ' +
+            '    (nao:identifier(?urn) AS ?identifier) ' +
+            '    (rdf:type(?urn) AS ?type) ' +
+            '    (nie:dataSource(?urn) AS ?datasource ) ' +
+            '    (( EXISTS { ?urn nco:contributor ?contributor FILTER ( ?contributor != ?creator ) } ) AS 
?shared) ' +
+            '    (nie:contentCreated(?urn) AS ?created) ';
         let whereSparql = this._buildWhere(global, flags);
         let tailSparql = '';
 
@@ -179,19 +189,44 @@ var QueryBuilder = new Lang.Class({
         }
 
         let sparql =
-            'SELECT DISTINCT ?urn ' + // urn
-            'nie:url(?urn) ' + // uri
-            'nfo:fileName(?urn) AS ?filename ' + // filename
-            'nie:mimeType(?urn)' + // mimetype
-            'nie:title(?urn) AS ?title ' + // title
-            'tracker:coalesce(nco:fullname(?creator), nco:fullname(?publisher), \'\') AS ?author ' + // 
author
-            'tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime ' + // 
mtime
-            'nao:identifier(?urn) ' + // identifier
-            'rdf:type(?urn) ' + // type
-            'nie:dataSource(?urn) ' + // resource URN
-            '( EXISTS { ?urn nco:contributor ?contributor FILTER ( ?contributor != ?creator ) } ) ' + // 
shared
-            'tracker:coalesce(nfo:fileCreated(?urn), nie:contentCreated(?urn)) ' + // date created
-            whereSparql + tailSparql;
+            'SELECT ?urn ' +
+            '  ?uri ' +
+            '  ?filename ' +
+            '  ?mimetype ' +
+            '  COALESCE (?localTitle, ?title) ' +
+            '  ?author ' +
+            '  ?mtime ' +
+            '  ?identifier ' +
+            '  ?type ' +
+            '  ?datasource ' +
+            '  ?shared ' +
+            '  ?created ' +
+            'WHERE { ';
+
+        // Collections queries are local
+        if (flags & QueryFlags.COLLECTIONS) {
+            sparql +=
+                'SELECT DISTINCT ?urn ' +
+                selectClauses +
+                whereSparql +
+                tailSparql;
+        } else {
+            sparql +=
+                'SERVICE <dbus:org.freedesktop.Tracker3.Miner.Files> {' +
+                '  GRAPH tracker:Documents { ' +
+                '    SELECT DISTINCT ?urn ' +
+                selectClauses +
+                whereSparql +
+                tailSparql +
+                '  }' +
+                '}' +
+                'OPTIONAL { ?urn nie:title ?localTitle } . ';
+
+                if (global && (flags & QueryFlags.UNFILTERED) == 0)
+                    sparql += this._context.documentManager.getWhere();
+        }
+
+        sparql += '}';
 
         return sparql;
     },
@@ -208,8 +243,18 @@ var QueryBuilder = new Lang.Class({
     },
 
     buildCountQuery: function(flags) {
-        let sparql = 'SELECT DISTINCT COUNT(?urn) ' +
-            this._buildWhere(true, flags);
+       let sparql;
+       if (flags & QueryFlags.COLLECTIONS) {
+           sparql = 'SELECT DISTINCT COUNT(?urn) AS ?c ' +
+               this._buildWhere(true, flags);
+       } else {
+           sparql = 'SELECT ?c {' +
+               '  SERVICE <dbus:org.freedesktop.Tracker3.Miner.Files> { ' +
+               '    SELECT DISTINCT COUNT(?urn) AS ?c ' +
+               this._buildWhere(true, flags) +
+               '  }' +
+               '}';
+       }
 
         return this._createQuery(sparql);
     },
@@ -219,8 +264,8 @@ var QueryBuilder = new Lang.Class({
         let sparql =
             ('SELECT ' +
              '?urn ' +
-             'tracker:coalesce(nfo:fileLastModified(?urn), nie:contentLastModified(?urn)) AS ?mtime ' +
-             'WHERE { ?urn nie:isPartOf ?collUrn } ' +
+             'nie:contentLastModified(?urn) AS ?mtime ' +
+             'WHERE { ?urn nie:isLogicalPartOf ?collUrn } ' +
              'ORDER BY DESC (?mtime)' +
              'LIMIT 4').replace(/\?collUrn/, '<' + resource + '>');
 
@@ -232,7 +277,7 @@ var QueryBuilder = new Lang.Class({
         let sparql =
             ('SELECT ' +
              '?urn ' +
-             'WHERE { ?urn a nfo:DataContainer . ?docUrn nie:isPartOf ?urn }'
+             'WHERE { ?urn a nfo:DataContainer . ?docUrn nie:isLogicalPartOf ?urn }'
             ).replace(/\?docUrn/, '<' + resource + '>');
 
         return this._createQuery(sparql);
@@ -240,15 +285,21 @@ var QueryBuilder = new Lang.Class({
 
     // adds or removes the given item to the given collection
     buildSetCollectionQuery: function(itemUrn, collectionUrn, setting) {
-        let sparql = ('%s { <%s> nie:isPartOf <%s> }'
-                     ).format((setting ? 'INSERT' : 'DELETE'), itemUrn, collectionUrn);
+        let sparql;
+        if (setting) {
+            sparql = ('INSERT DATA { <%s> a nie:InformationElement; nie:isLogicalPartOf <%s> }'
+                     ).format(itemUrn, collectionUrn);
+        } else {
+            sparql = ('DELETE DATA { <%s> nie:isLogicalPartOf <%s> }'
+                     ).format(itemUrn, collectionUrn);
+        }
         return this._createQuery(sparql);
     },
 
     // bumps the mtime to current time for the given resource
     buildUpdateMtimeQuery: function(resource) {
         let time = GdPrivate.iso8601_from_timestamp(GLib.get_real_time() / GLib.USEC_PER_SEC);
-        let sparql = ('INSERT OR REPLACE { <%s> nie:contentLastModified \"%s\" }'
+        let sparql = ('INSERT OR REPLACE { <%s> a nie:InformationElement ; nie:contentLastModified \"%s\" }'
                      ).format(resource, time);
 
         return this._createQuery(sparql);
diff --git a/src/search.js b/src/search.js
index 1a25f3ed..0bcc6d2c 100644
--- a/src/search.js
+++ b/src/search.js
@@ -19,6 +19,8 @@
  *
  */
 
+imports.gi.versions.Tracker = '3.0';
+
 const Application = imports.application;
 const Documents = imports.documents;
 const Manager = imports.manager;
@@ -126,11 +128,11 @@ const SearchTypeManager = new Lang.Class({
         this.addItem(new SearchType({ id: SearchTypeStock.EBOOKS,
                                       name: _("e-Books"),
                                       filter: '(nie:mimeType(?urn) IN (\"application/epub+zip\", 
\"application/x-mobipocket-ebook\", \"application/vnd.amazon.mobi8-ebook\", 
\"application/x-fictionbook+xml\", \"application/x-zip-compressed-fb2\", \"image/vnd.djvu+multipage\"))',
-                                      where: '?urn rdf:type nfo:FileDataObject .' }));
+                                      where: '?urn rdf:type nfo:EBook .' }));
         this.addItem(new SearchType({ id: SearchTypeStock.COMICS,
                                       name: _("Comics"),
                                       filter: '(nie:mimeType(?urn) IN (\"application/x-cbr\", 
\"application/vnd.comicbook-rar\", \"application/x-cbz\", \"application/vnd.comicbook+zip\", 
\"application/x-cbt\", \"application/x-cb7\"))',
-                                      where: '?urn rdf:type nfo:FileDataObject .' }));
+                                      where: '?urn rdf:type nfo:EBook .' }));
 
 
         this.setActiveItemById(SearchTypeStock.ALL);
@@ -322,7 +324,7 @@ const Source = new Lang.Class({
         let filters = [];
         locations.forEach(Lang.bind(this,
             function(location) {
-                filters.push('(fn:contains (nie:url(?urn), "%s"))'.format(location.get_uri()));
+                filters.push('(fn:contains (nie:isStoredAs(?urn), "%s"))'.format(location.get_uri()));
             }));
 
         filters.push('(fn:starts-with (nao:identifier(?urn), "gb:collection:local:"))');
diff --git a/src/trackerController.js b/src/trackerController.js
index e45f3a7f..17507e03 100644
--- a/src/trackerController.js
+++ b/src/trackerController.js
@@ -89,10 +89,10 @@ var TrackerConnectionQueue = new Lang.Class({
             Application.connection.query_async(params.query, params.cancellable,
                                           Lang.bind(this, this._queueCollector, params));
         else if (params.queryType == QueryType.UPDATE)
-            Application.connection.update_async(params.query, GLib.PRIORITY_DEFAULT, params.cancellable,
+            Application.connection.update_async(params.query, params.cancellable,
                                            Lang.bind(this, this._queueCollector, params));
         else if (params.queryType == QueryType.UPDATE_BLANK)
-            Application.connection.update_blank_async(params.query, GLib.PRIORITY_DEFAULT, 
params.cancellable,
+            Application.connection.update_blank_async(params.query, params.cancellable,
                                                  Lang.bind(this, this._queueCollector, params));
     },
 
diff --git a/src/trackerUtils.js b/src/trackerUtils.js
index a1653fed..c98a3345 100644
--- a/src/trackerUtils.js
+++ b/src/trackerUtils.js
@@ -24,7 +24,7 @@ const Lang = imports.lang;
 const Application = imports.application;
 
 function setEditedName(newTitle, docId, callback) {
-    let sparql = ('INSERT OR REPLACE { <%s> nie:title \"%s\" }'.format(docId, newTitle));
+    let sparql = ('INSERT OR REPLACE { <%s> a nie:InformationElement ; nie:title \"%s\" }'.format(docId, 
newTitle));
 
     Application.connectionQueue.update(sparql, null,
         function(object, res) {


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