tracker r1929 - in branches/xesam-support: . data/services src/trackerd



Author: mottela
Date: Thu Jul 24 15:01:58 2008
New Revision: 1929
URL: http://svn.gnome.org/viewvc/tracker?rev=1929&view=rev

Log:
Initial version of the xesam user query parser

Added:
   branches/xesam-support/src/trackerd/tracker-xesam-user-query.c
   branches/xesam-support/src/trackerd/tracker-xesam-user-query.h
Modified:
   branches/xesam-support/ChangeLog
   branches/xesam-support/data/services/xesam-metadata.mmapping
   branches/xesam-support/src/trackerd/Makefile.am
   branches/xesam-support/src/trackerd/tracker-xesam-query.c

Modified: branches/xesam-support/data/services/xesam-metadata.mmapping
==============================================================================
--- branches/xesam-support/data/services/xesam-metadata.mmapping	(original)
+++ branches/xesam-support/data/services/xesam-metadata.mmapping	Thu Jul 24 15:01:58 2008
@@ -765,7 +765,7 @@
 
 
 [xesam:url]
-MetaName=File:Name
+MetaName=File:Name;File:Path
 
 
 [xesam:useCount]

Modified: branches/xesam-support/src/trackerd/Makefile.am
==============================================================================
--- branches/xesam-support/src/trackerd/Makefile.am	(original)
+++ branches/xesam-support/src/trackerd/Makefile.am	Thu Jul 24 15:01:58 2008
@@ -63,6 +63,8 @@
 	tracker-xesam-manager.h						\
 	tracker-xesam-query.c						\
 	tracker-xesam-query.h						\
+	tracker-xesam-user-query.c					\
+	tracker-xesam-user-query.h					\
 	tracker-xesam-session.c						\
 	tracker-xesam-session.h						\
 	tracker-xesam-live-search.c					\

Modified: branches/xesam-support/src/trackerd/tracker-xesam-query.c
==============================================================================
--- branches/xesam-support/src/trackerd/tracker-xesam-query.c	(original)
+++ branches/xesam-support/src/trackerd/tracker-xesam-query.c	Thu Jul 24 15:01:58 2008
@@ -48,6 +48,7 @@
 #include <libtracker-common/tracker-utils.h>
 
 #include "tracker-xesam-query.h"
+#include "tracker-xesam-user-query.h"
 #include "tracker-db.h"
 
 /* XESAM Query Condition
@@ -394,7 +395,6 @@
 	field_data = NULL;
 	valid = TRUE;
 
-	/* Do the xesam mapping */
 	if (!strcmp(xesam_name,FIELD_NAME_FULL_TEXT_FIELDS)) {
 		result_set = tracker_db_xesam_get_all_text_metadata_names (data->iface);
 	} else {	
@@ -548,6 +548,48 @@
 			data->current_field = g_strdup (name);
 			push_stack (data, STATE_FIELD);
 		}
+	} else if (ELEMENT_IS (ELEMENT_XESAM_USER_QUERY)) {
+
+		if (set_error_on_fail (state == STATE_START,
+				       context, 
+				       "UserQuery element not expected here", 
+				       error)) {
+			return;
+		}
+
+		push_stack (data, STATE_USER_QUERY);
+	} else if (ELEMENT_IS (ELEMENT_XESAM_FIELD)) {
+		const gchar *name;
+
+		if (set_error_on_fail (is_operator (state), 
+				       context, 
+				       "Field element not expected here", 
+				       error)) {
+			return;
+		}
+
+		name = get_attribute_value_required (context,
+						     "<field>", 
+						     "name",
+						     attribute_names, 
+						     attribute_values,
+						     error);
+
+		if (!name) {
+			return;
+		} else {
+			if (data->current_operator == OP_NONE) {
+				set_error (error, 
+					   context, 
+					   PARSE_ERROR,
+					   "no operator found for field \"%s\"", 
+					   name);
+				return;
+			}
+
+			data->current_field = g_strdup (name);
+			push_stack (data, STATE_FIELD);
+		}
 	} else if (ELEMENT_IS (ELEMENT_XESAM_FULL_TEXT_FIELDS)) {
 
 		if (set_error_on_fail (is_operator (state), 
@@ -1192,6 +1234,26 @@
 		push_stack (data, STATE_END_QUERY);
 		data->query_okay = TRUE;
 
+	} else if (ELEMENT_IS (ELEMENT_XESAM_USER_QUERY)) {
+		TrackerXesamUserQuery *uq;
+		GError                *parse_error = NULL;
+		gchar                 *sql_where;
+
+		uq = tracker_xesam_user_query_new (data->current_value);
+
+		tracker_xesam_user_query_get_sql (uq, data->iface, &data->fields, &sql_where, &parse_error);
+
+		if (parse_error) {
+			g_propagate_error(error, parse_error);
+			return;
+		}
+
+		g_string_append (data->sql_where, sql_where);
+		g_free (sql_where);
+
+		push_stack (data, STATE_END_USER_QUERY);
+		data->query_okay = TRUE;
+
 	} else if (ELEMENT_IS (ELEMENT_XESAM_AND)) {
 
 		data->sql_where = g_string_append (data->sql_where, " ) ");
@@ -1357,6 +1419,7 @@
 		case STATE_DATE:
 		case STATE_FLOAT:
           	case STATE_BOOLEAN:
+        	case STATE_USER_QUERY:
 
 			data->current_value = g_strstrip (g_strndup (text, text_len));
 			break;

Added: branches/xesam-support/src/trackerd/tracker-xesam-user-query.c
==============================================================================
--- (empty file)
+++ branches/xesam-support/src/trackerd/tracker-xesam-user-query.c	Thu Jul 24 15:01:58 2008
@@ -0,0 +1,994 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* Tracker - indexer and metadata database engine
+ * Copyright (C) 2007-2008 Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#include <string.h>
+#include <math.h>
+#include <stdio.h>
+
+#include <glib-object.h>
+
+#include <trackerd/tracker-db.h>
+
+#include "tracker-xesam-user-query.h"
+
+#define TRACKER_XESAM_USER_QUERY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TRACKER_TYPE_XESAM_USER_QUERY, TrackerXesamUserQueryPrivate))
+
+typedef enum   CollectorType CollectorType;
+typedef enum   RelationType RelationType;
+typedef enum   TreeNodeType TreeNodeType;
+typedef struct TreeNode TreeNode;
+typedef struct TrackerXesamUserQueryPrivate TrackerXesamUserQueryPrivate;
+typedef struct ComposeHitsData ComposeHitsData;
+typedef struct SearchHitData SearchHitData;
+
+enum CollectorType {
+	COLLECTOR_UNDEF,
+	COLLECTOR_NONE,
+	COLLECTOR_RELATION,
+	COLLECTOR_IGNORE,
+	COLLECTOR_AND,
+	COLLECTOR_OR
+};
+
+enum RelationType {
+	REL_NONE,
+	REL_EQUAL,
+	REL_KEYWORD,
+	REL_LESS_OR_EQUAL,
+	REL_GREATER_OR_EQUAL,
+	REL_LESS,
+	REL_GREATER
+};
+
+struct TreeNode {
+	TreeNode      *left;
+	TreeNode      *right;
+	CollectorType  collector;
+
+	gchar         *keyword;
+	RelationType   relation;
+	gchar         *value;
+
+	/* operator modifiers */
+	gboolean       negate;
+
+	/* phrase modifiers */
+	gboolean       boost;
+	gboolean       case_sensitive;
+	gboolean       diacritic_sensitive;
+	gboolean       stemming;
+	gboolean       ordered;
+	gboolean       proximity;
+	gboolean       regular;
+	gboolean       sloppy;
+	gboolean       word_based;
+};
+
+struct TrackerXesamUserQueryPrivate {
+	gchar               *query_str;
+	TreeNode            *tree;
+	GQuark               error_quark;
+};
+
+enum {
+	PROP_0,
+	PROP_QUERY
+};
+
+
+
+static void tracker_xesam_user_query_class_init   (TrackerXesamUserQueryClass *class);
+static void tracker_xesam_user_query_init         (TrackerXesamUserQuery      *uq);
+static void tracker_xesam_user_query_finalize     (GObject               *object);
+static void tracker_xesam_user_query_set_property (GObject               *object,
+                                             guint                  prop_id,
+                                             const GValue          *value,
+                                             GParamSpec            *pspec);
+static void tracker_xesam_user_query_get_property (GObject               *object,
+                                             guint                  prop_id,
+                                             GValue                *value,
+                                             GParamSpec            *pspec);
+
+G_DEFINE_TYPE (TrackerXesamUserQuery, tracker_xesam_user_query, G_TYPE_OBJECT)
+
+static void
+tracker_xesam_user_query_class_init (TrackerXesamUserQueryClass *klass)
+{
+	GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+	object_class->finalize = tracker_xesam_user_query_finalize;
+	object_class->set_property = tracker_xesam_user_query_set_property;
+	object_class->get_property = tracker_xesam_user_query_get_property;
+
+	g_object_class_install_property (object_class,
+					 PROP_QUERY,
+					 g_param_spec_string ("query",
+							      "Query",
+							      "Query",
+							      NULL,
+							      G_PARAM_READWRITE));
+
+	g_type_class_add_private (object_class,
+				  sizeof (TrackerXesamUserQueryPrivate));
+}
+
+static void
+tracker_xesam_user_query_init (TrackerXesamUserQuery *uq)
+{
+	TrackerXesamUserQueryPrivate *priv;
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+
+	priv->error_quark = g_quark_from_static_string ("XESAM-user-parser-error-quark");
+}
+
+static TreeNode *
+tree_node_term_new (gchar *value)
+{
+	TreeNode *node;
+
+	node = g_slice_new0 (TreeNode);
+	node->value = g_strdup(value);
+	node->collector = COLLECTOR_NONE;
+
+	return node;
+}
+
+static TreeNode *
+tree_node_relation_new (const gchar *keyword)
+{
+	TreeNode *node;
+
+	node = g_slice_new0 (TreeNode);
+	node->keyword = g_strdup (keyword);
+	node->collector = COLLECTOR_RELATION;
+
+	return node;
+}
+
+static TreeNode *
+tree_node_collector_new (CollectorType collector)
+{
+	TreeNode *node;
+
+	node = g_slice_new0 (TreeNode);
+	node->collector = collector;
+
+	return node;
+}
+
+static void
+tree_node_free (TreeNode *node)
+{
+	if (!node)
+		return;
+
+	g_free (node->keyword);
+
+	tree_node_free (node->left);
+	tree_node_free (node->right);
+
+	g_slice_free (TreeNode, node);
+}
+
+void
+tree_node_set_value (TreeNode *node, gchar *value)
+{
+	/* FIXME Add checks */
+	node->value = g_strdup(value);
+}
+
+void
+tree_node_set_relation (TreeNode *node, RelationType relation)
+{
+	/* FIXME Add checks */
+	node->relation = relation;
+}
+
+void
+tree_node_set_modifiers (TreeNode *node, const gchar *modifiers)
+{
+	/* FIXME Add checks */
+
+	/* FIXME Implement */
+}
+
+
+static void
+tracker_xesam_user_query_finalize (GObject *object)
+{
+	TrackerXesamUserQueryPrivate *priv;
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (object);
+
+	tree_node_free (priv->tree);
+	g_free (priv->query_str);
+
+	G_OBJECT_CLASS (tracker_xesam_user_query_parent_class)->finalize (object);
+}
+
+static void
+tracker_xesam_user_query_set_property (GObject      *object,
+				       guint         prop_id,
+				       const GValue *value,
+				       GParamSpec   *pspec)
+{
+	switch (prop_id) {
+	case PROP_QUERY:
+		tracker_xesam_user_query_set_query (TRACKER_XESAM_USER_QUERY (object),
+					      g_value_get_string (value));
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+static void
+tracker_xesam_user_query_get_property (GObject      *object,
+				       guint         prop_id,
+				       GValue       *value,
+				       GParamSpec   *pspec)
+{
+	TrackerXesamUserQueryPrivate *priv;
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (object);
+
+	switch (prop_id) {
+	case PROP_QUERY:
+		g_value_set_string (value, priv->query_str);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	}
+}
+
+TrackerXesamUserQuery *
+tracker_xesam_user_query_new (const gchar     *query_str)
+{
+	g_return_val_if_fail (query_str != NULL, NULL);
+
+	return g_object_new (TRACKER_TYPE_XESAM_USER_QUERY,
+			     "query", query_str,			     
+			     NULL);
+}
+
+static void
+dump_tree (TreeNode *node)
+{
+	if (!node) {
+		g_print ("NULL ");
+		return;
+	}
+
+	switch (node->collector) {
+	case COLLECTOR_AND:
+		g_print ("AND \n(\n");
+		dump_tree (node->left);
+		dump_tree (node->right);
+		g_print ("\n)\n");
+		break;
+	case COLLECTOR_OR:
+		g_print ("OR \n(\n");
+		dump_tree (node->left);
+		dump_tree (node->right);
+		g_print ("\n)\n");
+		break;
+	default:
+		if (node->keyword) {
+			g_print ("%s ", node->keyword);
+		}
+
+		if (node->relation) {
+			g_print ("relation %d ", node->relation);
+		}
+
+		if (node->value) {
+			g_print ("And we have a value");
+		}
+	}
+}
+
+static void
+create_query_tree (TrackerXesamUserQuery *uq)
+{
+	TrackerXesamUserQueryPrivate *priv;
+	TreeNode                *node, *stack_node;
+	GQueue                  *queue, *stack;
+	CollectorType            collector;
+
+	gboolean                 last_was_collector = TRUE;
+	gboolean                 negate = FALSE;
+
+	gchar                   *string;
+	gchar                    value[100];
+
+	GScannerConfig config = {
+		"\t\r\n",                      /* characters to skip */
+		G_CSET_a_2_z "_" G_CSET_A_2_Z, /* identifier start */
+		G_CSET_a_2_z "_." G_CSET_A_2_Z G_CSET_DIGITS,/* identifier cont. */
+		"#\n",                         /* single line comment */
+		TRUE,                          /* case_sensitive */
+		TRUE,                          /* skip multi-line comments */
+		TRUE,                          /* skip single line comments */
+		FALSE,                         /* scan multi-line comments */
+		TRUE,                          /* scan identifiers */
+		TRUE,                          /* scan 1-char identifiers */
+		FALSE,                         /* scan NULL identifiers */
+		FALSE,                         /* scan symbols */
+		FALSE,                         /* scan binary */
+		FALSE,                         /* scan octal */
+		TRUE,                          /* scan float */
+		TRUE,                          /* scan hex */
+		FALSE,                         /* scan hex dollar */
+		TRUE,                          /* scan single quote strings */
+		TRUE,                          /* scan double quite strings */
+		TRUE,                          /* numbers to int */
+		FALSE,                         /* int to float */
+		TRUE,                          /* identifier to string */
+		TRUE,                          /* char to token */
+		FALSE,                         /* symbol to token */
+		FALSE,                         /* scope 0 fallback */
+		FALSE                          /* store int64 */
+	};
+	
+	GScanner      *scanner;
+	GTokenType     ttype;
+	GTokenType     peek_ttype;
+	const gchar   *query;
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+
+	queue = g_queue_new ();
+	stack = g_queue_new ();
+
+	scanner = g_scanner_new (&config);
+	query = tracker_xesam_user_query_get_query (uq);
+	g_scanner_input_text (scanner, query, strlen (query));
+
+	g_message ("Parsing xesam userQuery: %s", query);
+
+	for (peek_ttype = g_scanner_peek_next_token (scanner);
+	     peek_ttype != G_TOKEN_EOF;
+	     peek_ttype = g_scanner_peek_next_token (scanner)) {
+
+		collector = COLLECTOR_UNDEF;
+		node = NULL;
+
+		switch (peek_ttype) {
+			
+		case G_TOKEN_STRING:
+
+			if (strcmp (scanner->next_value.v_string, "AND") == 0 ||
+			    strcmp (scanner->next_value.v_string, "and") == 0) {
+
+				collector = COLLECTOR_AND;
+				ttype = g_scanner_get_next_token(scanner);
+				g_print ("\nAND\n");
+
+			} else if (strcmp (scanner->next_value.v_string, "OR") == 0 ||
+				   strcmp (scanner->next_value.v_string, "or") == 0) {
+
+				collector = COLLECTOR_OR;
+				ttype = g_scanner_get_next_token(scanner);
+				g_print ("\nOR\n");
+
+			} else {
+				
+				if (last_was_collector) {
+					collector = COLLECTOR_NONE;
+					g_print ("Term:");
+					ttype = g_scanner_get_next_token(scanner);
+				} else {
+					collector = COLLECTOR_AND;
+					g_print ("\nAssumed AND\n");
+				}
+			}
+			break;
+
+		case '+':
+			if (last_was_collector) {
+				collector = COLLECTOR_IGNORE;
+				ttype = g_scanner_get_next_token(scanner);
+
+				g_print ("Ignored (+)");
+			} else {
+				collector = COLLECTOR_AND;
+				ttype = g_scanner_get_next_token(scanner);
+
+				g_print ("\nAND (+)\n");
+			}
+			break;
+
+		case '-':
+			if (last_was_collector) {
+				collector = COLLECTOR_IGNORE;
+				/* FIXME negate the last collector */
+				ttype = g_scanner_get_next_token(scanner);
+			} else {
+				collector = COLLECTOR_AND;
+				negate = TRUE;
+			}
+			break;
+
+		case '&':
+			ttype = g_scanner_get_next_token(scanner);
+			if (g_scanner_peek_next_token (scanner) == '&') {			       
+				collector = COLLECTOR_AND;
+				ttype = g_scanner_get_next_token(scanner);
+			} else {
+				g_error ("Single '&' encountered.");
+			}
+			break;
+
+		case '|':
+			ttype = g_scanner_get_next_token(scanner);
+			if (g_scanner_peek_next_token (scanner) == '|') {			       
+				collector = COLLECTOR_OR;
+				ttype = g_scanner_get_next_token(scanner);
+			} else {
+				g_error ("Single '|' encountered.");
+			}			
+			break;
+			
+		case ' ':
+			collector = COLLECTOR_IGNORE;
+			ttype = g_scanner_get_next_token (scanner);
+			break;
+
+		default:
+			g_error ("Parse error. Unexpected type");
+		}
+		
+		switch (collector) {
+		case COLLECTOR_AND :
+			node = tree_node_collector_new (COLLECTOR_AND);
+			last_was_collector = TRUE;
+
+			g_queue_push_head (stack, node);
+			break;
+		
+		case COLLECTOR_OR:
+			node = tree_node_collector_new (COLLECTOR_OR);
+			last_was_collector = TRUE;
+
+			stack_node = g_queue_peek_head (stack);
+
+			while (stack_node && stack_node->collector == COLLECTOR_AND) {
+				stack_node = g_queue_pop_head (stack);
+				g_queue_push_head (queue, stack_node);
+
+				stack_node = g_queue_peek_head (stack);
+			}
+
+			g_queue_push_head (stack, node);
+			break;
+
+		case COLLECTOR_IGNORE:
+			/* Ignore */
+			break;
+
+		case COLLECTOR_NONE:
+
+			string = g_strdup(scanner->value.v_string);
+			last_was_collector = FALSE;
+
+			g_print ("String (%s) ", string);
+			peek_ttype = g_scanner_peek_next_token (scanner);
+			
+			if (peek_ttype == G_TOKEN_STRING) {
+				g_print ("for text search ");
+				node = tree_node_term_new (scanner->value.v_string);
+
+				ttype = g_scanner_get_next_token (scanner);
+				g_print ("with modifiers (%s)", scanner->value.v_string);
+				tree_node_set_modifiers (node, scanner->value.v_string);
+				
+			} else {
+				while ((peek_ttype = g_scanner_peek_next_token (scanner)) == ' ') {
+					ttype = g_scanner_get_next_token (scanner);
+				}
+
+				switch (peek_ttype) {
+				case '<' :
+				case '>' :
+					node = tree_node_relation_new (string);
+					ttype = g_scanner_get_next_token (scanner);
+					
+					if ((peek_ttype = g_scanner_peek_next_token (scanner)) == '=') {
+						g_print ("relation (%c%c) ", ttype, peek_ttype);
+						if (ttype == '>') {
+							tree_node_set_relation (node, REL_GREATER_OR_EQUAL);
+						} else {
+							tree_node_set_relation (node, REL_LESS_OR_EQUAL);
+						}
+
+						ttype = g_scanner_peek_next_token (scanner);
+					} else {
+						g_print ("relation (%c) ", ttype);
+						if (ttype == '>') {
+							tree_node_set_relation (node, REL_GREATER);
+						} else {
+							tree_node_set_relation (node, REL_LESS);
+						}
+						
+						ttype = g_scanner_peek_next_token (scanner);
+					}
+					
+					while ((ttype = g_scanner_get_next_token (scanner)) == ' ');
+					
+					switch (ttype) {
+					case G_TOKEN_STRING :
+						g_error ("Strings not expected for given relation"); 
+						break;
+						
+					case G_TOKEN_INT :
+						g_print ("int (%lu)", scanner->value.v_int);
+						sprintf (value, "%lu", scanner->value.v_int);
+						tree_node_set_value (node, value);
+						break;
+						
+					case G_TOKEN_FLOAT :
+						g_print ("float (%lf)",scanner->value.v_float);
+					        sprintf (value, "%lf", scanner->value.v_float);
+						tree_node_set_value (node, value);
+						break;
+						
+					default:
+						g_error ("Value type expected, not '%c'", (char) ttype);
+						break;
+					}
+					break;
+					
+				case ':' :
+				case '=' :
+					node = tree_node_relation_new (string);
+					ttype = g_scanner_get_next_token (scanner);
+
+					g_print ("relation (%c) ", ttype);
+					if (ttype == ':') {
+						tree_node_set_relation (node, REL_KEYWORD);
+					} else {
+						tree_node_set_relation (node, REL_EQUAL);
+					}
+					while ((ttype = g_scanner_get_next_token (scanner)) == ' ');
+					
+					switch (ttype) {
+					case G_TOKEN_STRING :
+						g_print ("string (%s)",scanner->value.v_string);
+						tree_node_set_value (node, scanner->value.v_string);
+						if ((peek_ttype = g_scanner_peek_next_token(scanner)) == G_TOKEN_STRING) {
+							ttype = g_scanner_get_next_token (scanner);
+							g_print ("with modifiers (%s)", scanner->value.v_string);
+							tree_node_set_modifiers (node, scanner->value.v_string);
+						}
+						break;
+						
+					case G_TOKEN_INT :
+						g_print ("int (%lu)",scanner->value.v_int);
+						sprintf (value, "%lu", scanner->value.v_int);
+						tree_node_set_value (node, value);
+						break;
+						
+					case G_TOKEN_FLOAT :
+						g_print ("float (%lf)",scanner->value.v_float);
+						sprintf (value, "%lf", scanner->value.v_float);
+						tree_node_set_value (node, value);
+						break;
+						
+					default:
+						g_error ("Value type expected, not '%c'", (char) ttype);
+						break;
+					}
+					break;
+					
+				default:
+					g_print ("which is a full text search.");
+					node = tree_node_term_new (string);
+					break;
+				}
+			}
+			g_free (string);
+
+			g_queue_push_head (queue, node);
+			break;
+	
+		default:
+			g_error ("Undefined operation");
+		}
+	}
+
+	g_print ("\nDone parsing. Processing.\n");
+
+	while ((stack_node = g_queue_pop_head (stack)) != NULL) {
+		g_queue_push_head (queue, stack_node);
+	}
+
+	while ((node = g_queue_pop_tail (queue)) != NULL) {
+		switch (node->collector) {
+		case COLLECTOR_AND:
+		case COLLECTOR_OR:
+			node->left = g_queue_pop_head (stack);
+			node->right = g_queue_pop_head (stack);
+			g_queue_push_head (stack, node);
+			break;
+		default:
+			g_queue_push_head (stack, node);
+			break;
+		}
+
+		priv->tree = node;
+	}
+
+
+	g_scanner_destroy (scanner);
+	g_queue_free (stack);
+	g_queue_free (queue);
+}
+
+static GList *
+add_metadata_field (TrackerDBInterface *iface,
+		    GSList     **fields, 
+		    const gchar *xesam_name)
+{
+	TrackerDBResultSet *result_set;
+	TrackerFieldData   *field_data;
+	gboolean            field_exists;
+	const GSList       *l;
+	GList              *reply;
+	gboolean            valid;
+	GString            *full_name;
+
+	reply = NULL;
+	field_exists = FALSE;
+	field_data = NULL;
+	valid = TRUE;
+
+	full_name = g_string_new (xesam_name);
+
+	full_name = g_string_prepend (full_name, "xesam:");
+
+	/* Do the xesam mapping */
+	result_set = tracker_db_xesam_get_metadata_names (iface, full_name->str);
+
+	if (!result_set) {
+		return NULL;
+	}
+
+	while (valid) {
+		gchar *field_name;
+		
+		tracker_db_result_set_get (result_set, 0, &field_name, -1);
+
+		/* Check if field is already in list */
+		for (l = *fields; l; l = l->next) {
+			const gchar *this_field_name;
+			
+			this_field_name = tracker_field_data_get_field_name (l->data);
+			
+			if (!this_field_name) {
+				continue;
+			}
+				
+			if (strcasecmp (this_field_name, field_name) == 0) {
+				field_data = l->data;
+				field_exists = TRUE;
+				
+				break;
+			}
+		}
+		
+		if (!field_exists) {
+			field_data = tracker_db_get_metadata_field (iface, 
+								    "Files", // FIXME This is a bogus value. Should we really need this?
+								    field_name, 
+								    g_slist_length (*fields), 
+								    FALSE, 
+								    TRUE);
+			if (field_data) {
+				*fields = g_slist_prepend (*fields, field_data);
+			} 
+		} 
+		
+		if (field_data) {
+			reply = g_list_append (reply, field_data);
+		}
+
+		valid = tracker_db_result_set_iter_next (result_set);
+		g_free (field_name);
+	}
+	
+	g_string_free (full_name, TRUE);
+
+	return reply;
+}
+
+
+gboolean
+create_sql (TrackerXesamUserQuery *uq, TreeNode *node, TrackerDBInterface *iface, GSList **fields, GString **sql, GError **error)
+{
+	GList *field_data_list = NULL;
+	GList *field_data = NULL;
+	const gchar  *where_field;
+	TrackerXesamUserQueryPrivate *priv;
+
+	g_return_val_if_fail (TRACKER_IS_XESAM_USER_QUERY (uq), FALSE);
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+
+	if (!node) {
+		g_print ("NULL ");
+		return TRUE;
+	}
+
+	switch (node->collector) {
+	case COLLECTOR_AND:
+		g_print (" AND (");
+
+		g_string_append_printf (*sql, "(");
+		g_print (" (call 1st)");
+		if (!create_sql (uq, node->left, iface, fields, sql, error)) {
+			g_print (" (failed) ");
+			return FALSE;
+		}
+		g_string_append_printf (*sql, " AND ");
+		g_print (" (call 2nd)");
+		if (!create_sql (uq, node->right, iface, fields, sql, error)) {
+			g_print (" (failed) ");
+			return FALSE;
+		}
+		g_string_append_printf (*sql, ")");
+		break;
+	case COLLECTOR_OR:
+		g_print (" OR ");
+
+		g_string_append_printf (*sql, "(");
+		g_print (" (call 1st)");
+		if (!create_sql (uq, node->left, iface, fields, sql, error)) {
+			g_print (" (failed) ");
+			return FALSE;
+		}
+		g_string_append_printf (*sql, " OR ");
+		g_print (" (call 2nd)");		
+		if (!create_sql (uq, node->right, iface, fields, sql, error)) {
+			g_print (" (failed) ");
+			return FALSE;
+		}
+		g_string_append_printf (*sql, ")");
+		break;
+	case COLLECTOR_RELATION:
+		g_print (" RELATION ");
+
+		switch (node->relation) {
+		case REL_KEYWORD:
+
+			if (strcmp(node->keyword, "type") == 0) {
+
+			} else {
+				
+				field_data_list = add_metadata_field (iface, fields, node->keyword);
+				
+				if (!field_data_list) {
+					g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+					return FALSE;
+				}
+				
+				g_string_append_printf (*sql, "(");
+				for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+					
+					if (field_data != field_data_list) {
+						g_string_append_printf (*sql, " OR ");
+					}
+					where_field = tracker_field_data_get_where_field (field_data->data);
+					g_string_append_printf (*sql, "(%s : %s)", where_field, node->value);
+				}
+				g_string_append_printf (*sql, ")");
+			}
+			break;
+			
+		case REL_EQUAL:
+			field_data_list = add_metadata_field (iface, fields, node->keyword);
+			
+			if (!field_data_list) {
+				g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+				return FALSE;
+			}
+			
+			g_string_append_printf (*sql, "(");
+			for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+				
+				if (field_data != field_data_list) {
+					g_string_append_printf (*sql, " OR ");
+				}
+				where_field = tracker_field_data_get_where_field (field_data->data);
+				g_string_append_printf (*sql, "(%s = %s)", where_field, node->value);
+			}
+			g_string_append_printf (*sql, ")");
+			break;
+
+		case REL_LESS_OR_EQUAL:
+			field_data_list = add_metadata_field (iface, fields, node->keyword);
+
+			if (!field_data_list) {
+				g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+				return FALSE;
+			}
+			
+			g_string_append_printf (*sql, "(");
+			for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+				
+				if (field_data != field_data_list) {
+					g_string_append_printf (*sql, " OR ");
+				}
+				where_field = tracker_field_data_get_where_field (field_data->data);
+				g_string_append_printf (*sql, "(%s <= %s)", where_field, node->value);
+			}
+			g_string_append_printf (*sql, ")");
+			break; 
+
+		case REL_GREATER_OR_EQUAL:
+			field_data_list = add_metadata_field (iface, fields, node->keyword);
+
+			if (!field_data_list) {
+				g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+				return FALSE;
+			}
+			
+			g_string_append_printf (*sql, "(");
+			for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+				
+				if (field_data != field_data_list) {
+					g_string_append_printf (*sql, " OR ");
+				}
+				where_field = tracker_field_data_get_where_field (field_data->data);
+				g_string_append_printf (*sql, "(%s >= %s)", where_field, node->value);
+			}
+			g_string_append_printf (*sql, ")");
+			break; 
+
+		case REL_LESS:
+			field_data_list = add_metadata_field (iface, fields, node->keyword);
+
+			if (!field_data_list) {
+				g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+				return FALSE;
+			}
+			
+			g_string_append_printf (*sql, "(");
+			for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+				
+				if (field_data != field_data_list) {
+					g_string_append_printf (*sql, " OR ");
+				}
+				where_field = tracker_field_data_get_where_field (field_data->data);
+				g_string_append_printf (*sql, "(%s < %s)", where_field, node->value);
+			}
+			g_string_append_printf (*sql, ")");
+			break; 
+
+		case REL_GREATER:
+			field_data_list = add_metadata_field (iface, fields, node->keyword);
+
+			if (!field_data_list) {
+				g_set_error (error, priv->error_quark, 1, "No such field: %s", node->keyword);
+				return FALSE;
+			}
+			
+			g_string_append_printf (*sql, "(");
+			for (field_data = field_data_list;field_data;field_data = g_list_next (field_data)) {
+				
+				if (field_data != field_data_list) {
+					g_string_append_printf (*sql, " OR ");
+				}
+				where_field = tracker_field_data_get_where_field (field_data->data);
+				g_string_append_printf (*sql, "(%s > %s)", where_field, node->value);
+			}
+			g_string_append_printf (*sql, ")");
+			break; 
+
+		default:
+			g_set_error (error, priv->error_quark, 1, "Unexpected relation type");
+			return FALSE;
+
+		}
+		break;
+	case COLLECTOR_NONE:
+		g_print (" NONE ");
+		
+		g_set_error (error, priv->error_quark, 1, "Full text search is not implemented yet");
+		
+		return FALSE;
+
+		break;
+	default:
+		g_set_error (error, priv->error_quark, 1, "Undefined operation");
+		return FALSE;
+		break;
+	}
+	
+	return TRUE;
+}
+
+
+void
+tracker_xesam_user_query_set_query (TrackerXesamUserQuery *uq,
+				    const gchar      *query_str)
+{
+	TrackerXesamUserQueryPrivate *priv;
+	gchar *str;
+
+	g_return_if_fail (TRACKER_IS_XESAM_USER_QUERY (uq));
+	g_return_if_fail (query_str != NULL);
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+
+	str = g_strdup (query_str);
+	g_free (priv->query_str);
+	priv->query_str = str;
+
+	/* construct the parse tree */
+	create_query_tree (uq);
+
+	g_object_notify (G_OBJECT (uq), "query");
+}
+
+G_CONST_RETURN gchar *
+tracker_xesam_user_query_get_query (TrackerXesamUserQuery *uq)
+{
+	TrackerXesamUserQueryPrivate *priv;
+
+	g_return_val_if_fail (TRACKER_IS_XESAM_USER_QUERY (uq), NULL);
+
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+	return priv->query_str;
+}
+
+gboolean
+tracker_xesam_user_query_get_sql (TrackerXesamUserQuery *uq, TrackerDBInterface *iface,
+				  GSList **fields, gchar **sql_where, GError **error)
+{
+	TrackerXesamUserQueryPrivate *priv;
+	GString *sql;
+
+	g_return_val_if_fail (sql_where != NULL, FALSE);
+
+	sql = g_string_new ("");
+
+	g_return_val_if_fail (TRACKER_IS_XESAM_USER_QUERY (uq), FALSE);
+	priv = TRACKER_XESAM_USER_QUERY_GET_PRIVATE (uq);
+
+	g_return_val_if_fail (TRACKER_IS_DB_INTERFACE (iface), FALSE);
+
+	g_return_val_if_fail (priv->tree != NULL, FALSE);
+
+	if (!create_sql (uq, priv->tree, iface, fields, &sql, error)) {
+		*sql_where = NULL;
+		return FALSE;
+	}
+	
+	g_print ("\nWe got:%s\n", sql->str);
+
+	g_string_prepend (sql, "WHERE ");
+
+	*sql_where = g_strdup (sql->str);
+	g_string_free (sql, TRUE);
+	return TRUE;
+
+}

Added: branches/xesam-support/src/trackerd/tracker-xesam-user-query.h
==============================================================================
--- (empty file)
+++ branches/xesam-support/src/trackerd/tracker-xesam-user-query.h	Thu Jul 24 15:01:58 2008
@@ -0,0 +1,75 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* 
+ * Copyright (C) 2008, Nokia
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA  02110-1301, USA.
+ */
+
+#ifndef __TRACKERD_XESAM_USER_QUERY_H__
+#define __TRACKERD_XESAM_USER_QUERY_H__
+
+#include <glib.h>
+
+#include <libtracker-db/tracker-db-interface.h>
+#include <libtracker-common/tracker-field-data.h>
+
+G_BEGIN_DECLS
+
+#include <glib-object.h>
+
+#define TRACKER_TYPE_XESAM_USER_QUERY         (tracker_xesam_user_query_get_type())
+#define TRACKER_XESAM_USER_QUERY(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), TRACKER_TYPE_XESAM_USER_QUERY, TrackerXesamUserQuery))
+#define TRACKER_XESAM_USER_QUERY_CLASS(c)     (G_TYPE_CHECK_CLASS_CAST ((c),    TRACKER_TYPE_XESAM_USER_QUERY, TrackerXesamUserQueryClass))
+#define TRACKER_IS_XESAM_USER_QUERY(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), TRACKER_TYPE_XESAM_USER_QUERY))
+#define TRACKER_IS_XESAM_USER_QUERY_CLASS(c)  (G_TYPE_CHECK_CLASS_TYPE ((c),    TRACKER_TYPE_XESAM_USER_QUERY))
+#define TRACKER_XESAM_USER_QUERY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),  TRACKER_TYPE_XESAM_USER_QUERY, TrackerXesamUserQueryClass))
+
+typedef struct TrackerXesamUserQuery TrackerXesamUserQuery;
+typedef struct TrackerXesamUserQueryClass TrackerXesamUserQueryClass;
+typedef struct TrackerSearchHit TrackerSearchHit;
+typedef struct TrackerHitCount TrackerHitCount;
+
+struct TrackerXesamUserQuery {
+	GObject parent;
+};
+
+struct TrackerXesamUserQueryClass {
+	GObjectClass parent_class;
+};
+
+
+GType                 tracker_xesam_user_query_get_type       (void);
+TrackerXesamUserQuery *    tracker_xesam_user_query_new       (const gchar      *query_str);
+
+
+
+G_CONST_RETURN gchar *tracker_xesam_user_query_get_query      (TrackerXesamUserQuery *tree);
+void                  tracker_xesam_user_query_set_query      (TrackerXesamUserQuery *tree,
+							       const gchar      *query_str);
+
+G_CONST_RETURN TrackerDBInterface *   tracker_xesam_user_query_get_iface      (TrackerXesamUserQuery *tree);
+void                  tracker_xesam_user_query_set_iface      (TrackerXesamUserQuery *tree,
+							       TrackerDBInterface    *query_str);
+
+gboolean              tracker_xesam_user_query_get_sql        (TrackerXesamUserQuery *tree,
+							       TrackerDBInterface    *iface,
+							       GSList               **fields,
+							       gchar                **sql_where,
+							       GError               **error);
+
+G_END_DECLS
+
+#endif /* __TRACKERD_XESAM_USER_QUERY_H__ */



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