protected virtual IEnumerable <Item> sortResult(IEnumerable <Item> iterable)
        {
            PersistentEnumerator src = (PersistentEnumerator)iterable.GetEnumerator();
            OidEnumerable        dst = new OidEnumerable(db);

            while (src.MoveNext())
            {
                dst.add(src.CurrentOid);
            }
            dst.sort();
            return(dst);
        }
        protected IEnumerable <Item> evaluate(Predicate predicate, bool sortNeeded)
        {
            IEnumerable <Item> iterator = null;

            if (predicate is Predicate.Compare)
            {
                Predicate.Compare cmp = (Predicate.Compare)predicate;
                int id;
                if (!db.name2id.TryGetValue(cmp.name, out id))
                {
                    return(getEmptyResultSet());
                }
                Index  index = (Index)db.storage.GetObjectByOID(id);
                Object value = cmp.value;
                switch (cmp.oper)
                {
                case Predicate.Compare.Operation.Equals:
                {
                    Key key = createKey(value, true);
                    return(new Item.ItemEnumerable(index.Range(key, key)));
                }

                case Predicate.Compare.Operation.LessThan:
                    return(new Item.ItemEnumerable(index.Range(null, createKey(value, false))));

                case Predicate.Compare.Operation.LessOrEquals:
                    iterator = new Item.ItemEnumerable(index.Range(null, createKey(value, true)));
                    break;

                case Predicate.Compare.Operation.GreaterThan:
                    iterator = new Item.ItemEnumerable(index.Range(createKey(value, false), null));
                    break;

                case Predicate.Compare.Operation.GreaterOrEquals:
                    iterator = new Item.ItemEnumerable(index.Range(createKey(value, true), null));
                    break;

                case Predicate.Compare.Operation.StartsWith:
                    iterator = new Item.ItemEnumerable(index.StartsWith(((String)value).ToLower()));
                    break;

                case Predicate.Compare.Operation.IsPrefixOf:
                    iterator = new ArrayEnumerable(index.PrefixSearch(((String)value).ToLower()));
                    break;

                case Predicate.Compare.Operation.InArray:
                {
                    OidEnumerable dst = new OidEnumerable(db);
                    if (value is String[])
                    {
                        String[] arr = (String[])value;
                        for (int i = 0; i < arr.Length; i++)
                        {
                            Key key = new Key(arr[i].ToLower());
                            PersistentEnumerator src = (PersistentEnumerator)index.GetEnumerator(key, key);
                            while (src.MoveNext())
                            {
                                dst.add(src.CurrentOid);
                            }
                        }
                    }
                    else if (value is double[])
                    {
                        double[] arr = (double[])value;
                        for (int i = 0; i < arr.Length; i++)
                        {
                            Key key = new Key(arr[i]);
                            PersistentEnumerator src = (PersistentEnumerator)index.GetEnumerator(key, key);
                            while (src.MoveNext())
                            {
                                dst.add(src.CurrentOid);
                            }
                        }
                    }
                    else
                    {
                        Item[] arr = (Item[])value;
                        for (int i = 0; i < arr.Length; i++)
                        {
                            Key key = new Key(arr[i]);
                            PersistentEnumerator src = (PersistentEnumerator)index.GetEnumerator(key, key);
                            while (src.MoveNext())
                            {
                                dst.add(src.CurrentOid);
                            }
                        }
                    }
                    dst.uniq();
                    return(dst);
                }
                }
            }
            else if (predicate is Predicate.And)
            {
                Predicate.And and = (Predicate.And)predicate;
                return(new JoinEnumerable(db, evaluate(and.left, true), evaluate(and.right, true)));
            }
            else if (predicate is Predicate.Or)
            {
                Predicate.Or or = (Predicate.Or)predicate;
                return(new MergeEnumerable(db, evaluate(or.left, true), evaluate(or.right, true)));
            }
            else if (predicate is Predicate.Between)
            {
                Predicate.Between between = (Predicate.Between)predicate;
                int id;
                if (!db.name2id.TryGetValue(between.name, out id))
                {
                    return(getEmptyResultSet());
                }
                Index index = (Index)db.storage.GetObjectByOID(id);
                iterator = new Item.ItemEnumerable(index.Range(createKey(between.from, true), createKey(between.till, true)));
            }
            else if (predicate is Predicate.Match)
            {
                Predicate.Match match = (Predicate.Match)predicate;
                iterator = new FullTextSearchResultEnumerable(db.root.fullTextIndex.Search(match.query, db.language, match.maxResults, match.timeLimit));
            }
            else if (predicate is Predicate.In)
            {
                Predicate.In isIn = (Predicate.In)predicate;
                int          id;
                if (!db.name2id.TryGetValue(isIn.name, out id))
                {
                    return(getEmptyResultSet());
                }
                Index         index = (Index)db.storage.GetObjectByOID(id);
                OidEnumerable dst   = new OidEnumerable(db);
                foreach (Item item in evaluate(isIn.subquery, false))
                {
                    Key key = new Key(item);
                    PersistentEnumerator src = (PersistentEnumerator)index.GetEnumerator(key, key);
                    while (src.MoveNext())
                    {
                        dst.add(src.CurrentOid);
                    }
                }
                dst.uniq();
                return(dst);
            }
            else
            {
                return(null);
            }
            return(sortNeeded ? sortResult(iterator) : iterator);
        }