Beispiel #1
0
        static public void SpewQuery(Query query)
        {
            int i = 0;

            foreach (QueryPart abstract_part in query.Parts)
            {
                ++i;

                if (abstract_part is QueryPart_Or)
                {
                    QueryPart_Or part = abstract_part as QueryPart_Or;
                    int          j    = 0;
                    Log.Spew("{0}: OR", i);
                    foreach (QueryPart sub_part in part.SubParts)
                    {
                        ++j;
                        Log.Spew("    {0}.{1}: {2}", i, j, QueryPartToString(sub_part));
                    }
                }
                else
                {
                    Log.Spew("{0}: {1}", i, QueryPartToString(abstract_part));
                }
            }
        }
        private void ThreadedImport()
        {
            query = new Query();
            query.AddDomain(QueryDomain.Neighborhood);
            query.MaxHits = 10000; // ugh?

            QueryPart_Property file_part = new QueryPart_Property();

            file_part.Type  = PropertyType.Keyword;
            file_part.Key   = "beagle:HitType";
            file_part.Value = "File";
            query.AddPart(file_part);

            QueryPart_Or query_part_union = new QueryPart_Or();

            foreach (string mimetype in supported_mime_types)
            {
                QueryPart_Property part = new QueryPart_Property();
                part.Type  = PropertyType.Keyword;
                part.Key   = "beagle:MimeType";
                part.Value = mimetype;
                query_part_union.Add(part);
            }

            query.AddPart(query_part_union);

            query.HitsAddedEvent += OnHitsAdded;
            query.FinishedEvent  += OnFinished;

            user_event                  = new ActiveUserEvent(Catalog.GetString("Import from Beagle"));
            user_event.Header           = Catalog.GetString("Importing from Beagle");
            user_event.Message          = Catalog.GetString("Running query...");
            user_event.Icon             = Icon;
            user_event.CancelRequested += OnCancelRequested;

            try {
                query.SendAsyncBlocking();
            } catch (Exception e) {
                DisposeQuery();
                LogCore.Instance.PushError(Catalog.GetString("Could not query Beagle Daemon"),
                                           e.Message, true);
                return;
            }

            if (SourceManager.ActiveSource is LibrarySource)
            {
                LibrarySource.Instance.Activate();
            }
        }
Beispiel #3
0
        // Returns an ICollection of QueryPart objects.
        static public ICollection Parse(string query_string)
        {
            Match m = query_string_regex.Match(query_string);

            ArrayList parts;

            parts = new ArrayList();

            ArrayList or_list = null;

            while (m.Success)
            {
                QueryPart query_part = MatchToQueryPart(m);

                if (or_list != null)
                {
                    or_list.Add(query_part);
                    query_part = null;
                }

                Match next = m.NextMatch();

                // Trap the OR operator
                // If the next match is an or, start an or_list
                // (if we don't have one already) and skip
                // ahead to the next part.
                if (next.Success &&
                    (next.Groups ["key"].ToString() == "") &&
                    (next.Groups ["midquote1"].ToString().ToUpper() == "OR"))
                {
                    if (or_list == null)
                    {
                        or_list = new ArrayList();
                        or_list.Add(query_part);
                    }

                    m = next.NextMatch();
                    continue;
                }

                // If we have a non-empty or-list going,
                // Create the appropriate QueryPart and add it
                // to the list.
                if (or_list != null)
                {
                    QueryPart_Or or_part = new QueryPart_Or();
                    or_part.Logic = QueryPartLogic.Required;

                    foreach (QueryPart sub_part in or_list)
                    {
                        or_part.Add(sub_part);
                    }

                    parts.Add(or_part);
                    or_list = null;
                }

                // Add the next text part
                if (query_part != null)
                {
                    parts.Add(query_part);
                }

                m = next;
            }

            // If we ended with an or_parts list, do the right thing.
            if (or_list != null)
            {
                QueryPart_Or or_part = new QueryPart_Or();
                or_part.Logic = QueryPartLogic.Required;

                foreach (QueryPart sub_part in or_list)
                {
                    or_part.Add(sub_part);
                }
            }

            return(parts);
        }
Beispiel #4
0
        static private QueryPart MatchToQueryPart(Match m)
        {
            // Looping over all Matches we have got:
            // m.Groups["pm"]       plus or minus sign
            // m.Groups["key"]      keyname
            // m.Groups["quote"]    quoted string
            // m.Groups["midquote1"] + m.Groups["midquote2"] quoted midway string also represents unquoted string

            string query = m.ToString();
            // Either quote is set or midquote1 and (optionally) midquote2 is set
            string text = m.Groups ["quote"].ToString() + m.Groups ["midquote1"].ToString() + m.Groups ["midquote2"].ToString();
            string key  = m.Groups ["key"].ToString();

            bool IsProhibited = (m.Groups ["pm"].ToString() == "-");


            // check for file extensions
            // if match starts with *. or . and only contains letters we assume it's a file extension
            if (extension_re.Match(text).Success || key.ToLower() == "ext" || key.ToLower() == "extension")
            {
                QueryPart_Property query_part = new QueryPart_Property();

                query_part.Key = Property.FilenameExtensionPropKey;

                if (text.StartsWith("*."))
                {
                    query_part.Value = text.Substring(1).ToLower();
                }
                else if (text.StartsWith("."))
                {
                    query_part.Value = text.ToLower();
                }
                else
                {
                    query_part.Value = "." + text.ToLower();
                }

                query_part.Type  = PropertyType.Keyword;
                query_part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

                Logger.Log.Debug("Extension query: {0}", query_part.Value);

                return(query_part);
            }

            if (key == String.Empty)
            {
                Logger.Log.Debug("Parsed query '{0}' as text_query", text);

                return(StringToQueryPart(text, IsProhibited));
            }

            // FIXME: i18n-izing "date"
            if (key == "date")
            {
                try {
                    QueryPart part = DateQueryToQueryPart(text);
                    part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                    return(part);
                } catch (FormatException) {
                    Log.Warn("Could not parse [{0}] as date query. Assuming text.", text);
                    return(StringToQueryPart(text, IsProhibited));
                }
            }

            // FIXME: i18n-izing "uri"
            if (key == "uri")
            {
                try {
                    QueryPart_Uri part = new QueryPart_Uri();
                    part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                    part.Uri   = UriFu.UserUritoEscapedUri(text);
                    return(part);
                } catch (System.UriFormatException) {
                    Log.Warn("Could not parse [{0}] as uri query. Assuming text.", text);
                    return(StringToQueryPart(text, IsProhibited));
                }
            }

            // Special case
            if (key == "inuri")
            {
                QueryPart_Property inuri_part = new QueryPart_Property();
                inuri_part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                inuri_part.Key   = "inuri";
                inuri_part.Value = text;
                inuri_part.Type  = PropertyType.Keyword;
                Log.Debug("Handing special query 'inuri:{0}'", text);
                return(inuri_part);
            }

            // Non-keyword queries by directly using property names
            // Query of form property:namespace:name=value
            // which is translated to a non-keyword query
            // namespace:name=value
            int pos;

            if (key == "property" && ((pos = text.IndexOf('=')) != -1))
            {
                QueryPart_Property part = new QueryPart_Property();
                part.Key   = text.Substring(0, pos);
                part.Value = text.Substring(pos + 1);
                part.Type  = PropertyType.Text;
                part.Logic = (IsProhibited ?      QueryPartLogic.Prohibited : QueryPartLogic.Required);
                Logger.Log.Debug("Parsed query '" + query +
                                 "' as prop query:key=" + part.Key +
                                 ", value=" + part.Value +
                                 " and property type=" + part.Type);

                return(part);
            }

            // keyword queries by directly using property names
            // Query of form keyword:namespace:name=value
            // which is translated to a keyword query
            // namespace:name=value
            if (key == "keyword" && ((pos = text.IndexOf('=')) != -1))
            {
                QueryPart_Property part = new QueryPart_Property();
                part.Key   = text.Substring(0, pos);
                part.Value = text.Substring(pos + 1);
                part.Type  = PropertyType.Keyword;
                part.Logic = (IsProhibited ?      QueryPartLogic.Prohibited : QueryPartLogic.Required);
                Logger.Log.Debug("Parsed query '" + query +
                                 "' as prop query:key=" + part.Key +
                                 ", value=" + part.Value +
                                 " and property type=" + part.Type);

                return(part);
            }

            if ((pos = text.IndexOf('*')) >= 0)
            {
                QueryPart_Wildcard wild = new QueryPart_Wildcard();
                wild.QueryString  = text;
                wild.PropertyOnly = true;
                return(wild);
            }

            string[] prop_string = null;
            bool     is_present;

            PropertyType[] prop_type;
            int            num;

            is_present = PropertyKeywordFu.GetMapping(key, out num, out prop_string, out prop_type);
            // if key is not present in the mapping, assume the query is a text query
            // i.e. if token is foo:bar and there is no mappable property named foo,
            // assume "foo:bar" as text query
            // FIXME the analyzer changes the text query "foo:bar" to "foo bar"
            // which might not be the right thing to do

            if (!is_present)
            {
                Logger.Log.Warn("Could not find property, parsed query '{0}' as text_query", query);

                return(StringToQueryPart(query, IsProhibited));
            }

            if (num == 1)
            {
                QueryPart_Property query_part_prop = new QueryPart_Property();
                query_part_prop.Key   = prop_string [0];
                query_part_prop.Value = text;
                query_part_prop.Type  = prop_type [0];
                query_part_prop.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

                Logger.Log.Debug("Parsed query '" + query +
                                 "' as prop query:key=" + query_part_prop.Key +
                                 ", value=" + query_part_prop.Value +
                                 " and property type=" + query_part_prop.Type);

                return(query_part_prop);
            }

            // Multiple property queries are mapped to this keyword query
            // Create an OR query from them
            // FIXME: Would anyone want an AND query ?

            QueryPart_Or query_part_or = new QueryPart_Or();

            query_part_or.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

            Logger.Log.Debug("Parsed query '{0}' as OR of {1} queries:", query, num);

            for (int i = 0; i < num; ++i)
            {
                QueryPart_Property query_part_prop = new QueryPart_Property();
                query_part_prop.Key   = prop_string [i];
                query_part_prop.Value = text;
                query_part_prop.Type  = prop_type [i];
                query_part_prop.Logic = QueryPartLogic.Required;

                Log.Debug("\t:key={0}, value={1} and property type={2}", query_part_prop.Key, query_part_prop.Value, query_part_prop.Type);
                query_part_or.Add(query_part_prop);
            }

            return(query_part_or);
        }
Beispiel #5
0
        static private Query NewRandomQuery(int length,
                                            bool allow_inexpensive,
                                            bool inside_an_or)
        {
            Query query;

            query = new Query();

            // One in four queries will contain some OR terms.
            if (!inside_an_or && random.Next(4) == 0)
            {
                int N = random.Next(3) + 1;
                for (int i = 0; i < N; ++i)
                {
                    QueryPart_Or part;
                    part = new QueryPart_Or();

                    int sub_length;
                    sub_length = random.Next(length) + 1;
                    if (sub_length < 2)
                    {
                        sub_length = 2;
                    }

                    // We generate a new query at random, and stuff its QueryParts
                    // into our Or QueryPart.
                    Query or_query;
                    or_query = NewRandomQuery(sub_length, allow_inexpensive, true);
                    foreach (QueryPart sub_part in or_query.Parts)
                    {
                        part.Add(sub_part);
                    }

                    query.AddPart(part);
                }
            }

            if (allow_inexpensive && !inside_an_or)
            {
                int mime_type;
                mime_type = random.Next(3);

                QueryPart_Or       mime_type_part = new QueryPart_Or();
                QueryPart_Property part;
                part      = new QueryPart_Property();
                part.Type = PropertyType.Keyword;
                part.Key  = "beagle:MimeType";

                if (mime_type == 0)
                {
                    part.Value = "inode/directory";
                    mime_type_part.Add(part);
                    query.AddPart(mime_type_part);
                }
                else if (mime_type == 1)
                {
                    part.Value = "text/plain";
                    mime_type_part.Add(part);
                    query.AddPart(mime_type_part);
                }
            }

            // Every query must contain at least
            // one required part.
            bool contains_required;

            contains_required = false;

            for (int i = 0; i < length; ++i)
            {
                QueryPart_Text part;
                part      = new QueryPart_Text();
                part.Text = Token.GetRandom();

                // Prohibited parts are not allowed inside an or
                if (contains_required && !inside_an_or)
                {
                    if (random.Next(2) == 0)
                    {
                        part.Logic = QueryPartLogic.Prohibited;
                    }
                }
                else
                {
                    // This part will be required.
                    contains_required = true;
                }

                if (random.Next(2) == 0)
                {
                    part.SearchTextProperties = false;
                }
                else if (allow_inexpensive && random.Next(2) == 0)
                {
                    part.SearchFullText = false;
                }

                query.AddPart(part);
            }

            // Note the ! inside_an_or; date range queries don't
            // work right inside OR queries when being searched
            // within the resolution of one day.  See the FIXME
            // about hit filters in LuceneCommon.cs
            if (allow_inexpensive && !inside_an_or && random.Next(3) == 0)
            {
                DateTime a, b;
                FileSystemObject.PickTimestampRange(out a, out b);

                QueryPart_DateRange part;
                part           = new QueryPart_DateRange();
                part.StartDate = a;
                part.EndDate   = b;
                query.AddPart(part);
            }

            return(query);
        }
Beispiel #6
0
                // Returns an ICollection of QueryPart objects.
                static public ICollection Parse (string query_string)
                {

                        Match m = query_string_regex.Match (query_string);

                        ArrayList parts;
                        parts = new ArrayList ();

                        ArrayList or_list = null;

                        while (m.Success) {

                                QueryPart query_part = MatchToQueryPart (m);

                                if (or_list != null) {
                                        or_list.Add (query_part);
                                        query_part = null;
                                }

                                Match next = m.NextMatch ();

                                // Trap the OR operator
                                // If the next match is an or, start an or_list
                                // (if we don't have one already) and skip
                                // ahead to the next part.
                                if ( next.Success
                                    && (next.Groups ["key"].ToString () == "")
                                    && (next.Groups ["midquote1"].ToString ().ToUpper () == "OR") ) {

                                        if (or_list == null) {
                                                or_list = new ArrayList ();
                                                or_list.Add (query_part);
                                        }

                                        m = next.NextMatch();
                                        continue;
                                }

                                // If we have a non-empty or-list going,
                                // Create the appropriate QueryPart and add it
                                // to the list.
                                if (or_list != null) {

                                        QueryPart_Or or_part = new QueryPart_Or ();
                                        or_part.Logic = QueryPartLogic.Required;

                                        foreach (QueryPart sub_part in or_list)
                                                or_part.Add (sub_part);

                                        parts.Add (or_part);
                                        or_list = null;
                                }

                                // Add the next text part
                                if (query_part != null)
                                        parts.Add (query_part);

                                m=next;
                        }

                        // If we ended with an or_parts list, do the right thing.
                        if (or_list != null) {

                                QueryPart_Or or_part = new QueryPart_Or ();
                                or_part.Logic = QueryPartLogic.Required;

                                foreach (QueryPart sub_part in or_list)
                                        or_part.Add (sub_part);
                        }

                        return parts;
                }
Beispiel #7
0
                static private QueryPart MatchToQueryPart (Match m)
                {
                        // Looping over all Matches we have got:
                        // m.Groups["pm"]       plus or minus sign
                        // m.Groups["key"]      keyname
                        // m.Groups["quote"]    quoted string
                        // m.Groups["midquote1"] + m.Groups["midquote2"] quoted midway string also represents unquoted string

                        string query = m.ToString ();
                        // Either quote is set or midquote1 and (optionally) midquote2 is set
                        string text = m.Groups ["quote"].ToString () + m.Groups ["midquote1"].ToString () + m.Groups ["midquote2"].ToString ();
                        string key = m.Groups ["key"].ToString ();

                        bool IsProhibited = (m.Groups ["pm"].ToString () == "-");


                        // check for file extensions
                        // if match starts with *. or . and only contains letters we assume it's a file extension
                        if (extension_re.Match (text).Success || key.ToLower () == "ext" || key.ToLower () == "extension") {

                                QueryPart_Property query_part = new QueryPart_Property ();

                                query_part.Key = Property.FilenameExtensionPropKey;

                                if (text.StartsWith ("*."))
                                        query_part.Value = text.Substring (1).ToLower ();
                                else if (text.StartsWith ("."))
                                        query_part.Value = text.ToLower ();
                                else
                                        query_part.Value = "." + text.ToLower ();

                                query_part.Type = PropertyType.Keyword;
                                query_part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

                                Logger.Log.Debug ("Extension query: {0}", query_part.Value);

                                return query_part;
                        }

                        if (key == String.Empty) {

                                Logger.Log.Debug ("Parsed query '{0}' as text_query", text);

                                return StringToQueryPart (text, IsProhibited);
                        }

                        // FIXME: i18n-izing "date"
                        if (key == "date") {
                                try {
                                        QueryPart part = DateQueryToQueryPart (text);
                                        part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                                        return part;
                                } catch (FormatException) {
                                        Log.Warn ("Could not parse [{0}] as date query. Assuming text.", text);
                                        return StringToQueryPart (text, IsProhibited);
                                }
                        }

                        // FIXME: i18n-izing "uri"
                        if (key == "uri") {
                                try {
                                        QueryPart_Uri part = new QueryPart_Uri ();
                                        part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                                        part.Uri = UriFu.UserUritoEscapedUri (text);
                                        return part;
                                } catch (System.UriFormatException) {
                                        Log.Warn ("Could not parse [{0}] as uri query. Assuming text.", text);
                                        return StringToQueryPart (text, IsProhibited);
                                }
                        }

                        // Special case
                        if (key == "inuri") {
                                QueryPart_Property inuri_part = new QueryPart_Property ();
                                inuri_part.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);
                                inuri_part.Key = "inuri";
                                inuri_part.Value = text;
                                inuri_part.Type = PropertyType.Keyword;
                                Log.Debug ("Handing special query 'inuri:{0}'", text);
                                return inuri_part;
                        }

                        // Non-keyword queries by directly using property names
                        // Query of form property:namespace:name=value
                        // which is translated to a non-keyword query
                        // namespace:name=value
                        int pos;
                        if (key == "property" && ((pos = text.IndexOf ('=')) != -1)) {
                                QueryPart_Property part = new QueryPart_Property ();
                                part.Key = text.Substring (0, pos);
                                part.Value = text.Substring (pos + 1);
                                part.Type = PropertyType.Text;
                                part.Logic = (IsProhibited ?      QueryPartLogic.Prohibited : QueryPartLogic.Required);
                                Logger.Log.Debug ("Parsed query '"          + query +
                                                  "' as prop query:key="    + part.Key +
                                                  ", value="                + part.Value +
                                                  " and property type="     + part.Type);

                                return part;
                        }

                        // keyword queries by directly using property names
                        // Query of form keyword:namespace:name=value
                        // which is translated to a keyword query
                        // namespace:name=value
                        if (key == "keyword" && ((pos = text.IndexOf ('=')) != -1)) {
                                QueryPart_Property part = new QueryPart_Property ();
                                part.Key = text.Substring (0, pos);
                                part.Value = text.Substring (pos + 1);
                                part.Type = PropertyType.Keyword;
                                part.Logic = (IsProhibited ?      QueryPartLogic.Prohibited : QueryPartLogic.Required);
                                Logger.Log.Debug ("Parsed query '"          + query +
                                                  "' as prop query:key="    + part.Key +
                                                  ", value="                + part.Value +
                                                  " and property type="     + part.Type);

                                return part;
                        }

                        if ((pos = text.IndexOf('*')) >= 0) {
                            QueryPart_Wildcard wild = new QueryPart_Wildcard();
                            wild.QueryString = text;
                            wild.PropertyOnly = true;
                            return wild;
                        }

                        string[] prop_string = null;
                        bool is_present;
                        PropertyType[] prop_type;
                        int num;

                        is_present = PropertyKeywordFu.GetMapping (key, out num, out prop_string, out prop_type);
                        // if key is not present in the mapping, assume the query is a text query
                        // i.e. if token is foo:bar and there is no mappable property named foo,
                        // assume "foo:bar" as text query
                        // FIXME the analyzer changes the text query "foo:bar" to "foo bar"
                        // which might not be the right thing to do

                        if (!is_present) {

                                Logger.Log.Warn ("Could not find property, parsed query '{0}' as text_query", query);

                                return StringToQueryPart (query, IsProhibited);
                        }

                        if (num == 1) {
                                QueryPart_Property query_part_prop = new QueryPart_Property ();
                                query_part_prop.Key = prop_string [0];
                                query_part_prop.Value = text;
                                query_part_prop.Type = prop_type [0];
                                query_part_prop.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

                                Logger.Log.Debug ("Parsed query '"          + query +
                                                  "' as prop query:key="    + query_part_prop.Key +
                                                  ", value="                + query_part_prop.Value +
                                                  " and property type="     + query_part_prop.Type);

                                return query_part_prop;
                        }

                        // Multiple property queries are mapped to this keyword query
                        // Create an OR query from them
                        // FIXME: Would anyone want an AND query ?

                        QueryPart_Or query_part_or = new QueryPart_Or ();
                        query_part_or.Logic = (IsProhibited ? QueryPartLogic.Prohibited : QueryPartLogic.Required);

                        Logger.Log.Debug ("Parsed query '{0}' as OR of {1} queries:", query, num);

                        for (int i = 0; i < num; ++i) {
                                QueryPart_Property query_part_prop = new QueryPart_Property ();
                                query_part_prop.Key = prop_string [i];
                                query_part_prop.Value = text;
                                query_part_prop.Type = prop_type [i];
                                query_part_prop.Logic = QueryPartLogic.Required;

                                Log.Debug ("\t:key={0}, value={1} and property type={2}", query_part_prop.Key, query_part_prop.Value, query_part_prop.Type);
                                query_part_or.Add (query_part_prop);
                        }

                        return query_part_or;
                }
		private QueryPart RemapInUriQueryPart (QueryPart_Property part)
		{
			string query = part.Value;

			if (query.StartsWith ("/"))
				query = UriFu.PathToFileUriString (query); // Make an URI

			if (query.StartsWith ("file:///")) {
				QueryPart_Property prop_part = new QueryPart_Property ();
				prop_part.Logic = part.Logic;
				prop_part.Key = Property.ParentDirUriPropKey;
				prop_part.Type = PropertyType.Keyword;

				Uri uri = ExternalToInternalUri (UriFu.EscapedStringToUri (query));
				if (uri == null)
					prop_part.Value = "no-match:///"; // FIXME: Returning null should work here
				else
					// From LuceneCommon.cs:AddPropertyToDocument since ParentDirUriPropKey is a private property
					prop_part.Value = UriFu.UriToEscapedString (uri);

				Log.Debug ("Remapped inuri={0} to {1}={2}", query, Property.ParentDirUriPropKey, prop_part.Value);
				return prop_part;
			}

			QueryPart_Or parent_dirs = new QueryPart_Or ();
			parent_dirs.Logic = part.Logic;

			lock (big_lock) {
				// Absolute path was not given.
				// Traverse the directories to find directories with _EXACTLY_ this name
				foreach (LuceneNameResolver.NameInfo info in uid_manager.GetAllDirectoryNameInfo (query)) {
					QueryPart_Property prop_part = new QueryPart_Property ();
					prop_part.Logic = QueryPartLogic.Required;
					prop_part.Type = PropertyType.Keyword;
					prop_part.Key = Property.ParentDirUriPropKey;
					prop_part.Value = GuidFu.ToUriString (info.Id);

					parent_dirs.Add (prop_part);
				}
			}

			Log.Debug ("Found {0} matching dirs with containing '{1}' in name", parent_dirs.SubParts.Count, query);
			if (parent_dirs.SubParts.Count == 0) {
				// Add dummy query to match nothing
				QueryPart_Property prop_part = new QueryPart_Property ();
				prop_part.Logic = QueryPartLogic.Required;
				prop_part.Type = PropertyType.Keyword;
				prop_part.Key = Property.ParentDirUriPropKey;
				prop_part.Value = "no-match:///";

				parent_dirs.Add (prop_part);
			}

			return parent_dirs;
		}