cvsimport
[beagle.git] / bludgeon / QueryFu.cs
blob18cb86376b9b7ac7ca3ed7a9f6d516edc7e7ac4a
2 using System;
3 using System.Collections;
4 using System.Threading;
6 using Beagle.Util;
7 using Beagle;
9 namespace Bludgeon {
11 public class QueryFu {
13 static public Query NewTokenQuery (string token)
15 Query query;
16 query = new Query ();
18 QueryPart_Text part;
19 part = new QueryPart_Text ();
20 part.Text = token;
21 query.AddPart (part);
23 return query;
26 static public Query NewTokenQuery (int id)
28 return NewTokenQuery (Token.IdToString (id));
31 static Random random = new Random ();
33 static public Query NewRandomQuery (int length,
34 bool allow_inexpensive)
36 return NewRandomQuery (length, allow_inexpensive, false);
39 static private Query NewRandomQuery (int length,
40 bool allow_inexpensive,
41 bool inside_an_or)
43 Query query;
44 query = new Query ();
46 // One in four queries will contain some OR terms.
47 if (! inside_an_or && random.Next (4) == 0) {
48 int N = random.Next (3) + 1;
49 for (int i = 0; i < N; ++i) {
50 QueryPart_Or part;
51 part = new QueryPart_Or ();
53 int sub_length;
54 sub_length = random.Next (length) + 1;
55 if (sub_length < 2)
56 sub_length = 2;
58 // We generate a new query at random, and stuff its QueryParts
59 // into our Or QueryPart.
60 Query or_query;
61 or_query = NewRandomQuery (sub_length, allow_inexpensive, true);
62 foreach (QueryPart sub_part in or_query.Parts)
63 part.Add (sub_part);
65 query.AddPart (part);
69 if (allow_inexpensive && ! inside_an_or) {
70 int mime_type;
71 mime_type = random.Next (3);
72 if (mime_type == 0)
73 query.AddMimeType ("inode/directory");
74 else if (mime_type == 1)
75 query.AddMimeType ("text/plain");
78 // Every query must contain at least
79 // one required part.
80 bool contains_required;
81 contains_required = false;
83 for (int i = 0; i < length; ++i) {
84 QueryPart_Text part;
85 part = new QueryPart_Text ();
86 part.Text = Token.GetRandom ();
88 // Prohibited parts are not allowed inside an or
89 if (contains_required && ! inside_an_or) {
90 if (random.Next (2) == 0)
91 part.Logic = QueryPartLogic.Prohibited;
92 } else {
93 // This part will be required.
94 contains_required = true;
97 if (random.Next (2) == 0)
98 part.SearchTextProperties = false;
99 else if (allow_inexpensive && random.Next (2) == 0)
100 part.SearchFullText = false;
102 query.AddPart (part);
105 // Note the ! inside_an_or; date range queries don't
106 // work right inside OR queries when being searched
107 // within the resolution of one day. See the FIXME
108 // about hit filters in LuceneCommon.cs
109 if (allow_inexpensive && ! inside_an_or && random.Next (3) == 0) {
110 DateTime a, b;
111 FileSystemObject.PickTimestampRange (out a, out b);
113 QueryPart_DateRange part;
114 part = new QueryPart_DateRange ();
115 part.StartDate = a;
116 part.EndDate = b;
117 query.AddPart (part);
120 return query;
123 static public Query NewRandomQuery ()
125 return NewRandomQuery (2 + random.Next (4), true);
128 /////////////////////////////////////////////////////////////
130 static public string QueryPartToString (QueryPart abstract_part)
132 string msg;
133 msg = "????";
135 if (abstract_part is QueryPart_Text) {
136 QueryPart_Text part;
137 part = (QueryPart_Text) abstract_part;
139 msg = part.Text;
140 if (! (part.SearchFullText && part.SearchTextProperties)) {
141 if (part.SearchFullText)
142 msg += " IN FULLTEXT";
143 else if (part.SearchTextProperties)
144 msg += " IN TEXT PROPERTIES";
145 } else
146 msg += " IN ANY TEXT";
148 } else if (abstract_part is QueryPart_Property) {
149 QueryPart_Property part;
150 part = (QueryPart_Property) abstract_part;
151 msg = String.Format ("PROPERTY {0} = {1}", part.Key, part.Value);
152 } else if (abstract_part is QueryPart_DateRange) {
153 QueryPart_DateRange part;
154 part = (QueryPart_DateRange) abstract_part;
155 msg = String.Format ("DATE RANGE {0} to {1}", part.StartDate, part.EndDate);
158 if (abstract_part.Logic == QueryPartLogic.Prohibited)
159 msg = "NOT " + msg;
162 return msg;
165 static public void SpewQuery (Query query)
167 int i = 0;
169 foreach (QueryPart abstract_part in query.Parts) {
171 ++i;
173 if (abstract_part is QueryPart_Or) {
174 QueryPart_Or part = abstract_part as QueryPart_Or;
175 int j = 0;
176 Log.Spew ("{0}: OR", i);
177 foreach (QueryPart sub_part in part.SubParts) {
178 ++j;
179 Log.Spew (" {0}.{1}: {2}", i, j, QueryPartToString (sub_part));
182 } else {
183 Log.Spew ("{0}: {1}", i, QueryPartToString (abstract_part));
188 /////////////////////////////////////////////////////////////
190 private class QueryClosure {
192 public Hashtable Hits;
193 private Query query;
195 public QueryClosure (Query query)
197 this.Hits = UriFu.NewHashtable ();
198 this.query = query;
201 public void OnHitsAdded (HitsAddedResponse response)
203 foreach (Hit hit in response.Hits)
204 Hits [hit.Uri] = hit;
207 public void OnFinished (FinishedResponse response)
209 query.Close ();
214 static public Hashtable GetHits (Query q)
216 QueryClosure qc;
217 qc = new QueryClosure (q);
218 q.HitsAddedEvent += qc.OnHitsAdded;
219 q.FinishedEvent += qc.OnFinished;
221 q.SendAsyncBlocking ();
223 return qc.Hits;
226 static public ICollection GetUris (Query q)
228 return GetHits (q).Keys;