banshee r2962 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Hyena src/Core/Hyena/Hyena.Data.Query
- From: gburt svn gnome org
- To: svn-commits-list gnome org
- Subject: banshee r2962 - in trunk/banshee: . src/Core/Banshee.Services/Banshee.Collection.Database src/Core/Hyena src/Core/Hyena/Hyena.Data.Query
- Date: Thu, 10 Jan 2008 21:40:15 +0000 (GMT)
Author: gburt
Date: Thu Jan 10 21:40:14 2008
New Revision: 2962
URL: http://svn.gnome.org/viewvc/banshee?rev=2962&view=rev
Log:
2008-01-10 Gabriel Burt <gabriel burt gmail com>
* src/Core/Hyena/Hyena.Data.Query/QueryNode.cs: Add ToUserQuery method to
rebuild what a user would type in the search bar from the object tree.
Add AppendXml and AppendUserQuery abstract methods.
* src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs:
For testing purposes, when a user searches, parse the query into the
QueryNode tree, generate XML from that, and then parse the XML.
* src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs: Implement
AppendUserQuery.
* src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs: Add Operator class and
implement AppendUserQuery and AppendXml. Generate XESAM-like XML (with
the goal of being compliant).
* src/Core/Hyena/Hyena.Data.Query/QueryParser.cs:
* src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs: Update copyright.
* src/Core/Hyena/Makefile.am:
* src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs: New file for parsing
XML queries into QueryNode trees.
Added:
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs
Modified:
trunk/banshee/ChangeLog
trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryNode.cs
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs
trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs
trunk/banshee/src/Core/Hyena/Makefile.am
Modified: trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs
==============================================================================
--- trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs (original)
+++ trunk/banshee/src/Core/Banshee.Services/Banshee.Collection.Database/TrackListDatabaseModel.cs Thu Jan 10 21:40:14 2008
@@ -83,6 +83,12 @@
//n.Dump ();
Console.WriteLine ("Xml for Query: {0}", n.ToXml ());
Console.WriteLine ("Sql for Query: {0}", filter_query);
+ Hyena.Data.Query.QueryParser qp2 = new XmlQueryParser (n.ToXml ());
+ QueryNode n2 = qp2.BuildTree ();
+ if (n2 != null) {
+ Console.WriteLine ("User query for Xml: {0}", n2.ToUserQuery ());
+ } else
+ Console.WriteLine ("n2 is null");
if (filter_query.Length == 0)
filter_query = null;
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryListNode.cs Thu Jan 10 21:40:14 2008
@@ -3,8 +3,9 @@
//
// Author:
// Aaron Bockover <abockover novell com>
+// Gabriel Burt <gburt novell com>
//
-// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2007-2008 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -159,7 +160,7 @@
if (ChildCount == 0)
return;
- XmlElement node = doc.CreateElement (Keyword.ToString ());
+ XmlElement node = doc.CreateElement (Keyword.ToString ().ToLower ());
parent.AppendChild (node);
foreach (QueryNode child in Children)
child.AppendXml (doc, node);
@@ -170,6 +171,34 @@
return String.Format("<{0}>", Keyword);
}
+ public override void AppendUserQuery (StringBuilder sb)
+ {
+ if (ChildCount == 0)
+ return;
+
+ if (Keyword != Keyword.Not) {
+ if (ChildCount > 1 && Parent != null)
+ sb.Append ("(");
+ bool first = true;
+ foreach (QueryNode child in Children) {
+ if (!first) {
+ if (Keyword == Keyword.Or)
+ sb.Append (", ");
+ else
+ sb.Append (" ");
+ } else {
+ first = false;
+ }
+ child.AppendUserQuery (sb);
+ }
+ if (ChildCount > 1 && Parent != null)
+ sb.Append (")");
+ } else {
+ sb.Append ("-");
+ Children [0].AppendUserQuery (sb);
+ }
+ }
+
public override void AppendSql (StringBuilder sb, QueryFieldSet fieldSet)
{
if (ChildCount == 0)
@@ -179,10 +208,11 @@
sb.Append ("(");
bool first = true;
foreach (QueryNode child in Children) {
- if (!first)
+ if (!first) {
sb.AppendFormat (" {0} ", Keyword);
- else
+ } else {
first = false;
+ }
child.AppendSql (sb, fieldSet);
}
sb.Append (")");
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryNode.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryNode.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryNode.cs Thu Jan 10 21:40:14 2008
@@ -3,8 +3,9 @@
//
// Author:
// Aaron Bockover <abockover novell com>
+// Gabriel Burt <gburt novell com>
//
-// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2007-2008 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -66,16 +67,31 @@
public abstract QueryNode Trim ();
- public abstract void AppendXml (XmlDocument doc, XmlNode parent);
+ public string ToUserQuery ()
+ {
+ StringBuilder sb = new StringBuilder ();
+ AppendUserQuery (sb);
+ return sb.ToString ();
+ }
+
+ public abstract void AppendUserQuery (StringBuilder sb);
public virtual string ToXml ()
{
XmlDocument doc = new XmlDocument ();
- AppendXml (doc, doc);
+
+ XmlElement request = doc.CreateElement ("request");
+ doc.AppendChild (request);
+
+ XmlElement query = doc.CreateElement ("query");
+ query.SetAttribute ("banshee-version", "1");
+ request.AppendChild (query);
+
+ AppendXml (doc, query);
return doc.OuterXml;
}
- public abstract void AppendSql (StringBuilder sb, QueryFieldSet fieldSet);
+ public abstract void AppendXml (XmlDocument doc, XmlNode parent);
public virtual string ToSql (QueryFieldSet fieldSet)
{
@@ -83,6 +99,8 @@
AppendSql (sb, fieldSet);
return sb.ToString ();
}
+
+ public abstract void AppendSql (StringBuilder sb, QueryFieldSet fieldSet);
public QueryListNode Parent {
get { return parent; }
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryParser.cs Thu Jan 10 21:40:14 2008
@@ -3,6 +3,7 @@
//
// Author:
// Aaron Bockover <abockover novell com>
+// Gabriel Burt <gburt novell com>
//
// Copyright (C) 2007 Novell, Inc.
//
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/QueryTermNode.cs Thu Jan 10 21:40:14 2008
@@ -3,8 +3,9 @@
//
// Author:
// Aaron Bockover <abockover novell com>
+// Gabriel Burt <gburt novell com>
//
-// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2007-2008 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
@@ -29,42 +30,76 @@
using System;
using System.Xml;
using System.Text;
+using System.Collections.Generic;
namespace Hyena.Data.Query
{
+ public class Operator
+ {
+ public string Name;
+ public string UserOperator;
+
+ private static List<Operator> operators = new List<Operator> ();
+ private static Dictionary<string, Operator> by_op = new Dictionary<string, Operator> ();
+ private static Dictionary<string, Operator> by_name = new Dictionary<string, Operator> ();
+
+ static Operator () {
+ // Note, order of these is important since if = was before ==, the value of the
+ // term would start with the second =, etc.
+ Add (new Operator ("equals", "=="));
+ Add (new Operator ("lessThanEquals", "<="));
+ Add (new Operator ("greaterThanEquals", ">="));
+ Add (new Operator ("startsWith", "="));
+ Add (new Operator ("contains", ":"));
+ Add (new Operator ("lessThan", "<"));
+ Add (new Operator ("greaterThan", ">"));
+ }
+
+ public static IEnumerable<Operator> Operators {
+ get { return operators; }
+ }
+
+ private static void Add (Operator op)
+ {
+ operators.Add (op);
+ by_op.Add (op.UserOperator, op);
+ by_name.Add (op.Name, op);
+ }
+
+ public static Operator GetByUserOperator (string op)
+ {
+ return (by_op.ContainsKey (op)) ? by_op [op] : null;
+ }
+
+ public static Operator GetByName (string name)
+ {
+ return (by_name.ContainsKey (name)) ? by_name [name] : null;
+ }
+
+ public Operator (string name, string userOp)
+ {
+ Name = name;
+ UserOperator = userOp;
+ }
+ }
+
public class QueryTermNode : QueryNode
{
private string field;
- private string value;
- private string op;
+ private string field_value;
+ private Operator op;
+
+ //private static string [] operators = new string [] {":", "==", "<=", ">=", "=", "<", ">"};
- /*public struct Operator
+ public QueryTermNode() : base ()
{
- public string [] UserQueryOperators;
- public string Label;
- public string Name;
- public string SqlFormat;
-
- public Operator (string name, string label, string sqlFormat, string [] operators)
- {
- Name = name;
- Label = label;
- SqlFormat = sqlFormat;
- UserQueryOperators = operators;
- }
-
- public static Operator
- }*/
-
- // Note, order of these is important since if = was before ==, the value of the
- // term would start with the second =, etc.
- private static string [] operators = new string [] {":", "==", "<=", ">=", "=", "<", ">"};
+ }
public QueryTermNode(string value) : base()
{
int field_separator = 0;
- foreach (string op in operators) {
- field_separator = value.IndexOf (op);
+ foreach (Operator op in Operator.Operators) {
+ field_separator = value.IndexOf (op.UserOperator);
if (field_separator != -1) {
this.op = op;
break;
@@ -73,16 +108,16 @@
if(field_separator > 0) {
field = value.Substring(0, field_separator);
- this.value = value.Substring(field_separator + op.Length);
+ this.field_value = value.Substring(field_separator + op.UserOperator.Length);
} else {
- this.value = value;
- this.op = ":";
+ this.field_value = value;
+ this.op = Operator.GetByUserOperator (":");
}
}
public override QueryNode Trim ()
{
- if (value == null || value == String.Empty)
+ if ((field_value == null || field_value == String.Empty) && Parent != null)
Parent.RemoveChild (this);
return this;
}
@@ -90,20 +125,33 @@
public override string ToString()
{
if(field != null) {
- return String.Format("[{0}]=\"{1}\"", field, value);
+ return String.Format("[{0}]=\"{1}\"", field, field_value);
} else {
return String.Format("\"{0}\"", Value);
}
}
- public override void AppendXml (XmlDocument doc, XmlNode parent)
+ public override void AppendUserQuery (StringBuilder sb)
{
- XmlElement node = doc.CreateElement ("term");
if (Field != null)
- node.SetAttribute ("field", Field);
- node.SetAttribute ("op", Operator);
- node.SetAttribute ("value", Value);
- parent.AppendChild (node);
+ sb.AppendFormat ("{0}{1}", Field, Operator.UserOperator);
+ sb.Append (Value);
+ }
+
+ public override void AppendXml (XmlDocument doc, XmlNode parent)
+ {
+ XmlElement op_node = doc.CreateElement (op.Name);
+ parent.AppendChild (op_node);
+
+ if (Field != null) {
+ XmlElement field = doc.CreateElement ("field");
+ field.SetAttribute ("name", Field);
+ op_node.AppendChild (field);
+ }
+
+ XmlElement val_node = doc.CreateElement ("string");
+ val_node.InnerText = Value;
+ op_node.AppendChild (val_node);
}
public override void AppendSql (StringBuilder sb, QueryFieldSet fieldSet)
@@ -145,7 +193,7 @@
if (emit_or)
sb.Append (" OR ");
- switch (Operator) {
+ switch (Operator.UserOperator) {
case "=": // Treat as starts with
case "==":
sb.AppendFormat("{0} LIKE '{1}%'", field, safe_value);
@@ -169,7 +217,7 @@
if (emit_or)
sb.Append (" OR ");
- switch (Operator) {
+ switch (Operator.UserOperator) {
case ":":
case "=":
case "==":
@@ -177,7 +225,7 @@
break;
default:
- sb.AppendFormat("{0} {2} {1}", field, num, Operator);
+ sb.AppendFormat("{0} {2} {1}", field, num, Operator.UserOperator);
break;
}
return true;
@@ -186,15 +234,18 @@
}
public string Value {
- get { return value; }
+ get { return field_value; }
+ set { field_value = value; }
}
- public string Operator {
+ public Operator Operator {
get { return op; }
+ set { op = value; }
}
public string Field {
get { return field; }
+ set { field = value; }
}
}
}
Modified: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs
==============================================================================
--- trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs (original)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/UserQueryParser.cs Thu Jan 10 21:40:14 2008
@@ -3,8 +3,9 @@
//
// Author:
// Aaron Bockover <abockover novell com>
+// Gabriel Burt <gburt novell com>
//
-// Copyright (C) 2007 Novell, Inc.
+// Copyright (C) 2007-2008 Novell, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
Added: trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs
==============================================================================
--- (empty file)
+++ trunk/banshee/src/Core/Hyena/Hyena.Data.Query/XmlQueryParser.cs Thu Jan 10 21:40:14 2008
@@ -0,0 +1,115 @@
+//
+// XmlQueryParser.cs
+//
+// Author:
+// Gabriel Burt <gburt novell com>
+//
+// Copyright (C) 2007-2008 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.IO;
+using System.Text;
+using System.Xml;
+
+namespace Hyena.Data.Query
+{
+ public class XmlQueryParser : QueryParser
+ {
+ private string str;
+
+ public XmlQueryParser () : base () {}
+ public XmlQueryParser (string str)
+ {
+ this.str = str;
+ }
+
+ public override QueryNode BuildTree ()
+ {
+ XmlDocument doc = new XmlDocument ();
+ try {
+ doc.LoadXml (str);
+ XmlElement request = doc.FirstChild as XmlElement;
+ if (request == null || request.Name != "request")
+ throw new Exception ("Invalid request");
+
+ XmlElement query = request.FirstChild as XmlElement;
+ if (query == null || query.Name != "query" || query.GetAttribute ("banshee-version") != "1")
+ throw new Exception ("Invalid query");
+
+ QueryNode node = Parse (query.FirstChild as XmlElement, null);
+ return (node != null) ? node.Trim () : null;
+ } catch (Exception e) {
+ Console.WriteLine ("Caught exception trying to parse query tree from XML: {0}", e.ToString ());
+ }
+ return null;
+ }
+
+ private QueryNode Parse (XmlElement node, QueryListNode parent)
+ {
+ if (node == null)
+ return null;
+
+ QueryListNode list = null;
+ Console.WriteLine ("Parsing node: {0}", node.Name);
+ switch (node.Name.ToLower ()) {
+ case "and":
+ list = new QueryListNode (Keyword.And);
+ break;
+ case "or":
+ list = new QueryListNode (Keyword.Or);
+ break;
+ case "not":
+ list = new QueryListNode (Keyword.Not);
+ break;
+ default:
+ QueryTermNode term = new QueryTermNode ();
+ term.Operator = Operator.GetByName (node.Name);
+
+ if (node["field"] != null)
+ term.Field = node["field"].GetAttribute ("name");
+
+ if (node["string"] != null)
+ term.Value = node["string"].InnerText;
+
+ if (parent != null)
+ parent.AddChild (term);
+ return term;
+ }
+
+ if (list != null) {
+ if (parent != null)
+ parent.AddChild (list);
+
+ foreach (XmlNode child in node.ChildNodes) {
+ Parse (child as XmlElement, list);
+ }
+ }
+
+ return list;
+ }
+
+ public override void Reset ()
+ {
+ }
+ }
+}
Modified: trunk/banshee/src/Core/Hyena/Makefile.am
==============================================================================
--- trunk/banshee/src/Core/Hyena/Makefile.am (original)
+++ trunk/banshee/src/Core/Hyena/Makefile.am Thu Jan 10 21:40:14 2008
@@ -18,6 +18,7 @@
Hyena.Data.Query/QueryParser.cs \
Hyena.Data.Query/QueryTermNode.cs \
Hyena.Data.Query/QueryToken.cs \
+ Hyena.Data.Query/XmlQueryParser.cs \
Hyena.Data.Query/UserQueryParser.cs \
Hyena.Data/CacheableModelAdapter.cs \
Hyena.Data/ColumnDescription.cs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]