[gnome-documents/wip/carlosg/tracker3: 20/22] Port queries to Tracker3




commit 3296833675ff48f7c578ac766aeac346e7911d68
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
    3) Queries g-o-m miners specifically, alongside local data
    
    All queries happen on the local connection, optionally including data
    from tracker-miner-fs and g-o-m miners via SERVICE{} clauses, this is
    just not the case for collection queries, since collections are stored
    in the private documents database.

 meson.build              |   4 +-
 src/application.js       |   8 ++-
 src/documents.js         |   2 +-
 src/main.js              |   3 +-
 src/query.js             | 136 ++++++++++++++++++++++++++++++++++++++---------
 src/search.js            |   4 +-
 src/trackerController.js |   4 +-
 src/trackerUtils.js      |   2 +-
 8 files changed, 127 insertions(+), 36 deletions(-)
---
diff --git a/meson.build b/meson.build
index 7a6d1ad0..1f63b310 100644
--- a/meson.build
+++ b/meson.build
@@ -54,7 +54,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')
@@ -68,8 +67,7 @@ documents_deps = [
   dependency('gobject-introspection-1.0', version: '>= 1.31.6'),
   dependency('gtk+-3.0', version: '>= 3.22.15'),
   dependency('libsoup-2.4', version: '>= 2.41.3'),
-  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 d1a1d454..73cd2da1 100644
--- a/src/application.js
+++ b/src/application.js
@@ -337,9 +337,13 @@ var Application = GObject.registerClass({
 
         // connect to tracker
         try {
-            connection = Tracker.SparqlConnection.get(null);
+            let cacheDir = GLib.build_filenamev([GLib.get_user_cache_dir(), 'org.gnome.Documents', '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 752b5714..d2ad55f9 100644
--- a/src/documents.js
+++ b/src/documents.js
@@ -776,7 +776,7 @@ const DocCommon = class DocCommon {
         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 b4afb261..9094f889 100644
--- a/src/main.js
+++ b/src/main.js
@@ -33,8 +33,7 @@ pkg.require({ 'EvinceDocument': '3.0',
               'Goa': '1.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 6ab1a462..4f5142ea 100644
--- a/src/query.js
+++ b/src/query.js
@@ -90,9 +90,6 @@ var QueryBuilder = class QueryBuilder {
             part += this._buildOptional();
 
             if ((flags & QueryFlags.UNFILTERED) == 0) {
-                if (global)
-                    part += this._context.documentManager.getWhere();
-
                 part += this._buildFilterString(currentType, flags, ftsQuery.length > 0);
             }
 
@@ -141,6 +138,18 @@ var QueryBuilder = class QueryBuilder {
     }
 
     _buildQueryInternal(global, flags, offsetController, sortBy) {
+        let selectClauses =
+            '    (COALESCE (nie:url(?urn), nie:isStoredAs(?urn)) AS ?uri) ' +
+            '    (COALESCE (nfo:fileName(?urn), tracker:string-from-filename(nie:isStoredAs(?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 = '';
 
@@ -175,19 +184,61 @@ var QueryBuilder = class QueryBuilder {
         }
 
         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, ?filename) AS ?t ' +
+            '  ?author ' +
+            '  ?mtime ' +
+            '  ?identifier ' +
+            '  ?type ' +
+            '  ?datasource ' +
+            '  ?shared ' +
+            '  ?created ' +
+            'WHERE { ';
+
+        // Collections queries are local
+        if (flags & QueryFlags.COLLECTIONS) {
+            sparql +=
+                'SELECT DISTINCT ?urn ' +
+                selectClauses +
+                whereSparql;
+        } else {
+           let services = ['org.freedesktop.Tracker3.Miner.Files'];
+           let serviceQueries = [];
+
+            if (this._context.sourceManager.hasProviderType('google'))
+               services.push('org.gnome.OnlineMiners.GData');
+            if (this._context.sourceManager.hasProviderType('owncloud'))
+               services.push('org.gnome.OnlineMiners.Owncloud');
+            if (this._context.sourceManager.hasProviderType('windows_live'))
+               services.push('org.gnome.OnlineMiners.Zpj');
+
+           services.forEach((service) => {
+               let serviceQuery =
+                   '{' +
+                    '  SERVICE SILENT <dbus:' + service + '> {' +
+                    '    GRAPH tracker:Documents { ' +
+                    '      SELECT DISTINCT ?urn ' +
+                    selectClauses +
+                    whereSparql +
+                    '    }' +
+                    '  }' +
+                   '}';
+
+               serviceQueries.push(serviceQuery);
+           });
+
+            sparql += serviceQueries.join(' UNION ');
+            sparql += 'OPTIONAL { ?urn nie:title ?localTitle } . ';
+
+            if (global && (flags & QueryFlags.UNFILTERED) == 0)
+                sparql += this._context.documentManager.getWhere();
+       }
+
+        sparql += '}';
+        sparql += tailSparql;
 
         return sparql;
     }
@@ -204,8 +255,39 @@ var QueryBuilder = class QueryBuilder {
     }
 
     buildCountQuery(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 {
+           let services = ['org.freedesktop.Tracker3.Miner.Files'];
+           let countQueries = [];
+
+            if (this._context.sourceManager.hasProviderType('google'))
+               services.push('org.gnome.OnlineMiners.GData');
+            if (this._context.sourceManager.hasProviderType('owncloud'))
+               services.push('org.gnome.OnlineMiners.Owncloud');
+            if (this._context.sourceManager.hasProviderType('windows_live'))
+               services.push('org.gnome.OnlineMiners.Zpj');
+
+           sparql = 'SELECT SUM(?c) {';
+
+           services.forEach((service) => {
+               let countQuery =
+                   '{ ' +
+                   '  SERVICE SILENT <dbus:' + service + '> { ' +
+                   '    GRAPH tracker:Documents { ' +
+                   '      SELECT DISTINCT COUNT(?urn) AS ?c ' +
+                   this._buildWhere(true, flags) +
+                   '    }' +
+                   '  }' +
+                   '}';
+               countQueries.push(countQuery);
+           });
+
+           sparql += countQueries.join(' UNION ');
+           sparql += '}';
+       }
 
         return this._createQuery(sparql);
     }
@@ -215,8 +297,8 @@ var QueryBuilder = class QueryBuilder {
         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 + '>');
 
@@ -228,7 +310,7 @@ var QueryBuilder = class QueryBuilder {
         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);
@@ -236,15 +318,21 @@ var QueryBuilder = class QueryBuilder {
 
     // adds or removes the given item to the given collection
     buildSetCollectionQuery(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(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 738ca336..557c7a0a 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;
@@ -328,7 +330,7 @@ const Source = class Source {
 
         let filters = [];
         locations.forEach((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), "gd:collection:local:"))');
diff --git a/src/trackerController.js b/src/trackerController.js
index 23e1c137..169ddcb5 100644
--- a/src/trackerController.js
+++ b/src/trackerController.js
@@ -86,10 +86,10 @@ var TrackerConnectionQueue = class TrackerConnectionQueue {
             Application.connection.query_async(params.query, params.cancellable,
                                                this._queueCollector.bind(this, 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,
                                                 this._queueCollector.bind(this, 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,
                                                       this._queueCollector.bind(this, params));
     }
 
diff --git a/src/trackerUtils.js b/src/trackerUtils.js
index 007568c1..1ed63f2e 100644
--- a/src/trackerUtils.js
+++ b/src/trackerUtils.js
@@ -22,7 +22,7 @@
 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]