sharp-oodb/Query.cs

222 lines
6.1 KiB
C#

using System;
using oodb.descriptor;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Metadata;
using System.Runtime.Remoting.Messaging;
using System.Collections;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Xsl.Runtime;
using oodb.index;
namespace oodb
{
public class QueryField
{
public string FieldName { get; }
public QueryField(String fieldName)
{
FieldName = fieldName;
}
public Predicate Contains(object value)
{
return new Predicate.Contains(this, value);
}
}
public abstract class Predicate
{
public QueryField QueryField { get; }
public Predicate(QueryField queryField)
{
QueryField = queryField;
}
public virtual bool MatchesTextValues => false;
public virtual bool TextMatch(string textValue) { throw new NotSupportedException(); }
public abstract bool Match(object value);
public OrPredicate Or => new OrPredicate(this);
public class OrPredicate : Predicate
{
public HashSet<Predicate> Predicates { get; } = new HashSet<Predicate>();
public OrPredicate(Predicate creator)
:base(creator.QueryField)
{
Predicates.Add(creator);
}
public OrPredicate Contains(object value)
{
Predicates.Add(new Predicate.Contains(this.QueryField, value));
return this;
}
public override bool MatchesTextValues
{
get {
foreach (Predicate predicate in Predicates)
if (!predicate.MatchesTextValues)
return false;
return true;
}
}
public override bool TextMatch(string textValue)
{
foreach (Predicate predicate in Predicates)
if (predicate.TextMatch(textValue))
return true;
return false;
}
public override bool Match(object value)
{
foreach (Predicate predicate in Predicates)
if (predicate.Match(value))
return true;
return false;
}
}
public class Contains : Predicate
{
public object Value { get; }
public Contains(QueryField queryField,object value)
:base(queryField)
{
Value = value;
}
public override bool Match(object value)
{
if ((Value == null) || String.Empty.Equals(Value))
return true;
if (value == null)
return false;
return (value as string).Contains(Value as string);
}
}
}
public class Query<T> where T: Persistent
{
public virtual AlternativesQuery<T> Or(Query<T> alternativeQuery) => new AlternativesQuery<T>(this, alternativeQuery);
public virtual AlternativesQuery<T> Or(params Predicate[] predicates) => new AlternativesQuery<T>(this, new Query<T>(predicates));
public HashSet<Predicate> Predicates { get; } = new HashSet<Predicate>();
protected Query()
{
}
public Query(IEnumerable<Predicate> predicates)
{
foreach (Predicate predicate in predicates)
{
Predicates.Add(predicate);
}
}
public Query(params Predicate[] predicates)
{
foreach (Predicate predicate in predicates)
{
Predicates.Add(predicate);
}
}
public IEnumerable<Predicate> GetPredicates(QueryField queryField)
{
return Predicates.Where((x) => x.QueryField == queryField);
}
public virtual IEnumerable<T> Search(OODB oodb)
{
Descriptor descriptor = oodb.GetDescriptor<T>();
HashSet<QueryField> predicateFields = new HashSet<QueryField>();
foreach (Predicate predicate in Predicates)
{
predicateFields.Add(predicate.QueryField);
}
Guid[] results = null;
foreach (QueryField queryField in predicateFields)
{
FieldInfo fieldInfo = descriptor.GetFieldInfo(queryField.FieldName);
if (!oodb.StorageAdapter.HasSearchIndex(fieldInfo))
throw new NotSupportedException("Queries must use indexed fields");
SearchIndex searchIndex = oodb.StorageAdapter.GetSearchIndex(fieldInfo);
foreach (Predicate predicate in GetPredicates(queryField))
{
IEnumerable<Guid> myresults = searchIndex.Query(predicate);
if (results == null)
{
results = myresults.ToArray();
} else {
results = results.Intersect(myresults).ToArray();
}
}
}
return results.Select((id)=>oodb.Load<T>(id));
}
}
public class AlternativesQuery<T> : Query<T> where T:Persistent
{
public HashSet<Query<T>> Alternatives = new HashSet<Query<T>>();
public AlternativesQuery(params Query<T>[] queries)
{
foreach (Query<T> alternative in queries)
Alternatives.Add(alternative);
}
public override AlternativesQuery<T> Or(Query<T> alternativeQuery)
{
Alternatives.Add(alternativeQuery);
return this;
}
public override AlternativesQuery<T> Or(params Predicate[] predicates)
{
Alternatives.Add(new Query<T>(predicates));
return this;
}
public override IEnumerable<T> Search(OODB oodb)
{
return Alternatives.SelectMany((alternative) => alternative.Search(oodb)).Distinct();
}
}
}