[evolution-ews] Implement e_book_backend_sqlitedb_search.



commit 2f08cca8bb4904a7ee1ce7d906d8f9e1b70ef6a2
Author: Chenthill Palanisamy <pchenthill novell com>
Date:   Mon Apr 25 16:31:48 2011 +0530

    Implement e_book_backend_sqlitedb_search.

 src/addressbook/e-book-backend-sqlitedb.c |  336 ++++++++++++++++++++++++++++-
 src/addressbook/e-book-backend-sqlitedb.h |    4 +
 2 files changed, 338 insertions(+), 2 deletions(-)
---
diff --git a/src/addressbook/e-book-backend-sqlitedb.c b/src/addressbook/e-book-backend-sqlitedb.c
index 998a105..834165f 100644
--- a/src/addressbook/e-book-backend-sqlitedb.c
+++ b/src/addressbook/e-book-backend-sqlitedb.c
@@ -24,6 +24,8 @@
 
 #include <glib/gi18n.h>
 #include <libebook/e-contact.h>
+#include <libedataserver/e-sexp.h>
+#include <libedata-book/e-book-backend-sexp.h>
 
 #include "e-sqlite3-vfs.h"
 #include "e-book-backend-sqlitedb.h"
@@ -215,6 +217,7 @@ create_folders_table	(EBookBackendSqliteDB *ebsdb,
 	gint ret;
 	const gchar *stmt = "CREATE TABLE IF NOT EXISTS folders		\
 			     ( folder_id  TEXT PRIMARY KEY,		\
+			       folder_name TEXT,			\
 			       sync_data TEXT,		 		\
 			       bdata1 TEXT, bdata2 TEXT,		\
 			       bdata3 TEXT)";
@@ -226,6 +229,7 @@ create_folders_table	(EBookBackendSqliteDB *ebsdb,
 	return ret;
 }
 
+/* The column names match the fields used in book-backend-sexp */
 static gint
 create_contacts_table	(EBookBackendSqliteDB *ebsdb,
 			 const gchar *folderid,
@@ -236,8 +240,8 @@ create_contacts_table	(EBookBackendSqliteDB *ebsdb,
 		
 	stmt = sqlite3_mprintf ("CREATE TABLE IF NOT EXISTS %Q	 		\
 			     ( uid  TEXT PRIMARY KEY,				\
-			       nickname TEXT, fullname TEXT,			\
-			       given_name TEXT, surname TEXT,			\
+			       nickname TEXT, full_name TEXT,			\
+			       given_name TEXT, family_name TEXT,		\
 			       email_1 TEXT, email_2 TEXT,			\
 			       email_3 TEXT, email_4 TEXT,			\
 			       vcard TEXT)", folderid);
@@ -538,3 +542,331 @@ e_book_backend_sqlitedb_get_vcard_string	(EBookBackendSqliteDB *ebsdb,
 	
 	return vcard_str;	
 }
+
+static ESExpResult *
+func_check (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
+{
+	ESExpResult *r;
+	gint truth = FALSE;
+
+	if (argc == 2
+	    && argv[0]->type == ESEXP_RES_STRING
+	    && argv[1]->type == ESEXP_RES_STRING) {
+		gchar *query_name = argv[0]->value.string;
+
+		if (!strcmp (query_name, "nickname") ||
+		    !strcmp (query_name, "full_name") ||
+		    !strcmp (query_name, "file_as") ||
+		    !strcmp (query_name, "email")) {
+			truth = TRUE;
+		}
+	}
+
+	r = e_sexp_result_new (f, ESEXP_RES_BOOL);
+	r->value.boolean = truth;
+
+	return r;
+}
+
+/* 'builtin' functions */
+static const struct {
+	const gchar *name;
+	ESExpFunc *func;
+	gint type;		/* set to 1 if a function can perform shortcut evaluation, or
+				   doesn't execute everything, 0 otherwise */
+} check_symbols[] = {
+	{ "contains", func_check, 0 },
+	{ "is", func_check, 0 },
+	{ "beginswith", func_check, 0 },
+	{ "endswith", func_check, 0 },
+	{ "exists", func_check, 0 }
+};
+
+static gboolean
+book_backend_sqlitedb_is_summary_query (const gchar *query)
+{
+	ESExp *sexp;
+	ESExpResult *r;
+	gboolean retval;
+	gint i;
+	gint esexp_error;
+
+	sexp = e_sexp_new ();
+
+	for (i = 0; i < G_N_ELEMENTS (check_symbols); i++) {
+		if (check_symbols[i].type == 1) {
+			e_sexp_add_ifunction (sexp, 0, check_symbols[i].name,
+					     (ESExpIFunc *)check_symbols[i].func, NULL);
+		} else {
+			e_sexp_add_function (sexp, 0, check_symbols[i].name,
+					    check_symbols[i].func, NULL);
+		}
+	}
+
+	e_sexp_input_text (sexp, query, strlen (query));
+	esexp_error = e_sexp_parse (sexp);
+
+	if (esexp_error == -1) {
+		return FALSE;
+	}
+
+	r = e_sexp_eval (sexp);
+
+	retval = (r && r->type == ESEXP_RES_BOOL && r->value.boolean);
+
+	e_sexp_result_free (sexp, r);
+
+	e_sexp_unref (sexp);
+
+	return retval;
+}
+
+static ESExpResult *
+func_or (ESExp *f, gint argc, struct _ESExpTerm **argv, gpointer data)
+{
+	ESExpResult *r, *r1;
+	GString *string;
+	gint i;
+
+	string = g_string_new("( ");
+	for (i = 0; i < argc; i++) {
+		r1 = e_sexp_term_eval (f, argv[i]);
+
+		if (r1->type != ESEXP_RES_STRING) {
+			e_sexp_result_free (f, r1);
+			continue;
+		}
+		g_string_append_printf(string, "%s%s", r1->value.string, ((argc>1) && (i != argc-1)) ?  " OR ":"");
+		e_sexp_result_free (f, r1);
+	}
+	g_string_append(string, " )");
+
+	r = e_sexp_result_new (f, ESEXP_RES_STRING);
+	r->value.string = string->str;
+	g_string_free (string, FALSE);
+	return r;
+}
+
+
+typedef enum {
+	MATCH_CONTAINS,
+	MATCH_IS,
+	MATCH_BEGINS_WITH,
+	MATCH_ENDS_WITH
+} match_type;
+
+static ESExpResult *
+convert_match_exp (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data, match_type match)
+{
+	ESExpResult *r;
+	gchar *str=NULL;
+
+	/* are we inside a match-all? */
+	if (argc>1 && argv[0]->type == ESEXP_RES_STRING) {
+		const gchar *field;
+
+		/* only a subset of headers are supported .. */
+		field = argv[0]->value.string;
+
+		if (argv[1]->type == ESEXP_RES_STRING && argv[1]->value.string [0] != 0) {
+			gchar *value=NULL;
+			
+			if (match == MATCH_CONTAINS) {
+				value = g_strdup_printf ("%%%s%%", argv[1]->value.string);
+			} else if (match == MATCH_ENDS_WITH) {
+				value = g_strdup_printf ("%%%s", argv[1]->value.string);
+			} else if (match == MATCH_BEGINS_WITH) {
+				value = g_strdup_printf ("%s%%", argv[1]->value.string);
+			} else if (match == MATCH_IS) {
+				value = g_strdup_printf ("%%%s%%", argv[1]->value.string);
+			}
+			
+			if (!strcmp (value, "full_name")) {
+				gchar *full, *sur, *given, *nick;
+
+				full = g_strdup_printf("(full_name IS NOT NULL AND full_name LIKE %s)",value);
+				sur = g_strdup_printf("(family_name IS NOT NULL AND family_name LIKE %s)",value);
+				given = g_strdup_printf("(given_name IS NOT NULL AND given_name LIKE %s)",value);
+				nick = g_strdup_printf("(nick_name IS NOT NULL AND nick_name LIKE %s)",value);
+			
+				str = g_strdup_printf (" %s OR %s OR %s OR %s ", full, sur, given, nick);
+
+				g_free (full);
+				g_free (sur);
+				g_free (given);
+				g_free (nick);
+			} else if (!strcmp (value, "email")) {
+				gint i;	
+				GString *emails = g_string_new (NULL);
+				
+				for (i = 1; i < 4; i++) {
+					g_string_append_printf (emails, "(email_%d IS NOT NULL AND email_%d LIKE %s)", i, i, value);
+					g_string_append (emails, " OR ");
+				}
+				g_string_append_printf (emails, "(email_4 IS NOT NULL AND email_4 LIKE %s)", value);
+
+				str = emails->str;
+				g_string_free (emails, FALSE);
+			} else
+				str = g_strdup_printf("(%s IS NOT NULL AND %s LIKE %s)", field, field, value);
+			g_free (value);
+		}
+	}
+
+	r = e_sexp_result_new (f, ESEXP_RES_STRING);
+	r->value.string = str;
+
+	return r;
+}
+
+static ESExpResult *
+func_contains (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
+{
+	return convert_match_exp (f, argc, argv, data, MATCH_CONTAINS);
+}
+
+static ESExpResult *
+func_is (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
+{
+	return convert_match_exp (f, argc, argv, data, MATCH_IS);
+}
+
+static ESExpResult *
+func_beginswith (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
+{
+	return convert_match_exp (f, argc, argv, data, MATCH_BEGINS_WITH);
+}
+
+static ESExpResult *
+func_endswith (struct _ESExp *f, gint argc, struct _ESExpResult **argv, gpointer data)
+{
+	return convert_match_exp (f, argc, argv, data, MATCH_ENDS_WITH);
+}
+
+/* 'builtin' functions */
+static struct {
+	const gchar *name;
+	ESExpFunc *func;
+	guint immediate :1;
+} symbols[] = {
+	{ "or", (ESExpFunc *) func_or, 1},
+
+	{ "contains", func_contains, 0 },
+	{ "is", func_is, 0 },
+	{ "beginswith", func_beginswith, 0 },
+	{ "endswith", func_endswith, 0 },
+};
+
+static char *
+sexp_to_sql_query (const gchar *query)
+{
+	ESExp *sexp;
+	ESExpResult *r;
+	gint i;
+	gchar *res;
+
+	sexp = e_sexp_new ();
+
+	for (i = 0; i < G_N_ELEMENTS (symbols); i++) {
+		if (symbols[i].immediate)
+			e_sexp_add_ifunction (sexp, 0, symbols[i].name,
+					     (ESExpIFunc *) symbols[i].func, NULL);
+		else
+			e_sexp_add_function (sexp, 0, symbols[i].name,
+					    symbols[i].func, NULL);
+	}
+
+	e_sexp_input_text (sexp, query, strlen (query));
+	e_sexp_parse (sexp);
+
+	r = e_sexp_eval (sexp);
+	if (!r)
+		return NULL;
+	if (r->type == ESEXP_RES_STRING) {
+		res = g_strdup (r->value.string);
+	} else
+		g_assert (0);
+
+	e_sexp_result_free (sexp, r);
+	e_sexp_unref (sexp);
+	return res;
+}
+
+static gint
+addto_vcard_list_cb (gpointer ref, gint col, gchar **cols, gchar **name)
+{
+	GList **vcards = ref;
+
+	if (cols [0])
+		*vcards = g_list_prepend (*vcards, cols [0]);
+
+	return 0;
+}
+
+static GList *
+book_backend_sqlitedb_search_query (EBookBackendSqliteDB *ebsdb, const gchar *sql, const gchar *folderid, GError **error)
+{
+	GList *vcards = NULL;
+	gchar *stmt;
+	
+	READER_LOCK (ebsdb);
+
+	stmt = sqlite3_mprintf ("SELECT vcard FROM %Q WHERE %s", folderid, sql);
+	book_backend_sql_exec (ebsdb->priv->db, stmt, addto_vcard_list_cb , &vcards, error);
+	sqlite3_free (stmt);
+
+	READER_UNLOCK (ebsdb);
+
+	vcards = g_list_reverse (vcards);
+	
+	return vcards;
+}
+
+static GList *
+book_backend_sqlitedb_search_full (EBookBackendSqliteDB *ebsdb, const gchar *sexp, const gchar *folderid, GError **error)
+{
+	GList *vcards = NULL, *all = NULL, *l;
+	EBookBackendSExp *bsexp = NULL;
+	gchar *stmt;
+	
+	READER_LOCK (ebsdb);
+
+	stmt = sqlite3_mprintf ("SELECT vcard FROM %Q", folderid);
+	book_backend_sql_exec (ebsdb->priv->db, stmt, addto_vcard_list_cb , &all, error);
+	sqlite3_free (stmt);
+
+	READER_UNLOCK (ebsdb);
+
+	bsexp = e_book_backend_sexp_new (sexp);
+	
+	for (l = all; l != NULL; l = g_list_next (l)) {
+		if (e_book_backend_sexp_match_vcard (bsexp, l->data))
+			vcards = g_list_prepend (vcards, g_strdup (l->data));
+	}
+
+	g_object_unref (bsexp);
+	g_list_foreach (all, (GFunc) g_free, NULL);
+	g_list_free (all);
+
+	return vcards;
+
+}
+
+GList *
+e_book_backend_sqlitedb_search	(EBookBackendSqliteDB *ebsdb,
+				 const gchar *folderid,
+				 const gchar *sexp,
+				 GError **error)
+{
+	GList *vcards = NULL;
+
+	if (book_backend_sqlitedb_is_summary_query (sexp)) {
+		char *sql_query;
+
+		sql_query = sexp_to_sql_query (sexp);
+		vcards = book_backend_sqlitedb_search_query (ebsdb, sql_query, folderid, error);
+	} else
+		vcards = book_backend_sqlitedb_search_full (ebsdb, sexp, folderid, error);
+
+	return vcards;
+}
diff --git a/src/addressbook/e-book-backend-sqlitedb.h b/src/addressbook/e-book-backend-sqlitedb.h
index dfb4b8a..ea6f441 100644
--- a/src/addressbook/e-book-backend-sqlitedb.h
+++ b/src/addressbook/e-book-backend-sqlitedb.h
@@ -86,6 +86,10 @@ const gchar *	e_book_backend_sqlitedb_get_vcard_string
 							 const gchar *folderid,
 							 const gchar *uid,
 							 GError **error);
+GList *		e_book_backend_sqlitedb_search		(EBookBackendSqliteDB *ebsdb,
+							 const gchar *folderid,
+							 const gchar *sexp,
+							 GError **error);
 
 G_END_DECLS
 



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