[tracker] libtracker-data: Implement tracker:title-order() SPARQL function



commit 80606e70475409f1e3dea47aee15a4c3b038aef9
Author: Carlos Garnacho <carlosg gnome org>
Date:   Tue Jul 18 17:58:27 2017 +0200

    libtracker-data: Implement tracker:title-order() SPARQL function
    
    This is a tracker-specific helper function that will remove the
    initial common articles (the, a, an, ...) for sorting purposes.
    This is implemented as an additional collation, so tracker:title-order
    only makes sense to be used in the ORDER BY clause.

 po/POTFILES.in                                     |    1 +
 src/libtracker-data/libtracker-data.vapi           |    3 +
 src/libtracker-data/tracker-collation.c            |   77 ++++++++++++++++++++
 src/libtracker-data/tracker-collation.h            |    6 ++
 src/libtracker-data/tracker-db-interface-sqlite.c  |   10 +++
 src/libtracker-data/tracker-db-interface-sqlite.h  |    1 +
 src/libtracker-data/tracker-sparql-expression.vala |    4 +
 7 files changed, 102 insertions(+), 0 deletions(-)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 886a09f..47d9b3e 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -6,6 +6,7 @@ src/libtracker-common/tracker-dbus.c
 src/libtracker-common/tracker-utils.c
 src/libtracker-fts/org.freedesktop.Tracker.FTS.gschema.xml.in
 src/libtracker-data/org.freedesktop.Tracker.DB.gschema.xml.in
+src/libtracker-data/tracker-collation.c
 src/libtracker-data/tracker-data-backup.c
 src/libtracker-miner/tracker-data-provider.c
 src/libtracker-miner/tracker-miner-fs.c
diff --git a/src/libtracker-data/libtracker-data.vapi b/src/libtracker-data/libtracker-data.vapi
index b2582c8..ba09968 100644
--- a/src/libtracker-data/libtracker-data.vapi
+++ b/src/libtracker-data/libtracker-data.vapi
@@ -247,6 +247,9 @@ namespace Tracker {
        [CCode (cheader_filename = "libtracker-data/tracker-db-interface-sqlite.h")]
        public const string COLLATION_NAME;
 
+       [CCode (cheader_filename = "libtracker-data/tracker-db-interface-sqlite.h")]
+       public const string TITLE_COLLATION_NAME;
+
        [CCode (cheader_filename = "libtracker-data/tracker-collation.h")]
        public const unichar COLLATION_LAST_CHAR;
 }
diff --git a/src/libtracker-data/tracker-collation.c b/src/libtracker-data/tracker-collation.c
index b43ce91..2e28a17 100644
--- a/src/libtracker-data/tracker-collation.c
+++ b/src/libtracker-data/tracker-collation.c
@@ -19,6 +19,7 @@
 
 #include "config.h"
 #include <glib.h>
+#include <glib/gi18n.h>
 #include <string.h>
 #include <locale.h>
 
@@ -239,3 +240,79 @@ tracker_collation_utf8 (gpointer      collator,
 }
 
 #endif
+
+static gboolean
+check_remove_prefix (const gchar  *str,
+                     gint          len,
+                     const gchar  *prefix,
+                     gint          prefix_len,
+                     const gchar **str_out,
+                     gint         *len_out)
+{
+       gboolean substituted = FALSE;
+       gchar *strstart;
+
+       if (len <= prefix_len)
+               return FALSE;
+
+       strstart = g_utf8_casefold (str, prefix_len);
+       if (strcmp (strstart, prefix) == 0) {
+               *str_out = str + prefix_len;
+               *len_out = len - prefix_len;
+               substituted = TRUE;
+       }
+
+       g_free (strstart);
+
+       return substituted;
+}
+
+/* Helper function valid for all implementations */
+gint
+tracker_collation_utf8_title (gpointer      collator,
+                              gint          len1,
+                              gconstpointer str1,
+                              gint          len2,
+                              gconstpointer str2)
+{
+       const gchar *title_beginnings_str;
+       static gchar **title_beginnings = NULL;
+       const gchar *res1 = NULL, *res2 = NULL;
+       gint i;
+
+       /* Translators: this is a space-separated list of common title
+        * beginnings. Meant to be skipped for sorting purposes, case
+        * doesn't matter. Given English media is quite common, it is
+        * advised to leave the untranslated articles in addition to
+        * the translated ones.
+        */
+       title_beginnings_str = N_("the a an");
+
+       if (!title_beginnings)
+               title_beginnings = g_strsplit (_(title_beginnings_str), " ", -1);
+
+       for (i = 0; title_beginnings[i]; i++) {
+               gchar *prefix, *str;
+               gint prefix_len;
+
+               str = g_strdup_printf ("%s ", title_beginnings[i]);
+               prefix = g_utf8_casefold (str, -1);
+               prefix_len = strlen (prefix);
+
+               if (!res1)
+                       check_remove_prefix (str1, len1, prefix, prefix_len,
+                                            &res1, &len1);
+               if (!res2)
+                       check_remove_prefix (str2, len2, prefix, prefix_len,
+                                            &res2, &len2);
+               g_free (prefix);
+               g_free (str);
+       }
+
+       if (!res1)
+               res1 = str1;
+       if (!res2)
+               res2 = str2;
+
+       return tracker_collation_utf8 (collator, len1, res1, len2, res2);
+}
diff --git a/src/libtracker-data/tracker-collation.h b/src/libtracker-data/tracker-collation.h
index 93afae2..d3e5af1 100644
--- a/src/libtracker-data/tracker-collation.h
+++ b/src/libtracker-data/tracker-collation.h
@@ -34,6 +34,12 @@ gint     tracker_collation_utf8     (gpointer      collator,
                                      gint          len2,
                                      gconstpointer str2);
 
+gint     tracker_collation_utf8_title (gpointer      collator,
+                                       gint          len1,
+                                       gconstpointer str1,
+                                       gint          len2,
+                                       gconstpointer str2);
+
 #ifdef HAVE_LIBICU
 #define TRACKER_COLLATION_LAST_CHAR ((gunichar) 0x10fffd)
 #else
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.c 
b/src/libtracker-data/tracker-db-interface-sqlite.c
index 2b62d70..a001e2f 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.c
+++ b/src/libtracker-data/tracker-db-interface-sqlite.c
@@ -1848,6 +1848,16 @@ tracker_db_interface_sqlite_reset_collator (TrackerDBInterface *db_interface)
                g_critical ("Couldn't set collation function: %s",
                            sqlite3_errmsg (db_interface->db));
        }
+
+       if (sqlite3_create_collation_v2 (db_interface->db,
+                                        TRACKER_TITLE_COLLATION_NAME,
+                                        SQLITE_UTF8,
+                                        tracker_collation_init (),
+                                        tracker_collation_utf8_title,
+                                        tracker_collation_shutdown) != SQLITE_OK) {
+               g_critical ("Couldn't set title collation function: %s",
+                           sqlite3_errmsg (db_interface->db));
+       }
 }
 
 static gint
diff --git a/src/libtracker-data/tracker-db-interface-sqlite.h 
b/src/libtracker-data/tracker-db-interface-sqlite.h
index 5c81c66..49fab3c 100644
--- a/src/libtracker-data/tracker-db-interface-sqlite.h
+++ b/src/libtracker-data/tracker-db-interface-sqlite.h
@@ -31,6 +31,7 @@ G_BEGIN_DECLS
 #endif
 
 #define TRACKER_COLLATION_NAME "TRACKER"
+#define TRACKER_TITLE_COLLATION_NAME "TRACKER_TITLE"
 
 typedef void (*TrackerDBWalCallback) (TrackerDBInterface *iface,
                                       gint                n_pages);
diff --git a/src/libtracker-data/tracker-sparql-expression.vala 
b/src/libtracker-data/tracker-sparql-expression.vala
index 27b65a4..338dc20 100644
--- a/src/libtracker-data/tracker-sparql-expression.vala
+++ b/src/libtracker-data/tracker-sparql-expression.vala
@@ -522,6 +522,10 @@ class Tracker.Sparql.Expression : Object {
                        translate_expression_as_string (sql);
                        sql.append (")");
                        return PropertyType.STRING;
+               } else if (uri == TRACKER_NS + "title-order") {
+                       translate_expression_as_string (sql);
+                       sql.append_printf (" COLLATE %s", TITLE_COLLATION_NAME);
+                       return PropertyType.STRING;
                } else if (uri == FN_NS + "lower-case") {
                        // conversion to string
                        sql.append ("SparqlLowerCase (");


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