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 Predicates { get; } = new HashSet(); 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 where T: Persistent { public virtual AlternativesQuery Or(Query alternativeQuery) => new AlternativesQuery(this, alternativeQuery); public virtual AlternativesQuery Or(params Predicate[] predicates) => new AlternativesQuery(this, new Query(predicates)); public HashSet Predicates { get; } = new HashSet(); protected Query() { } public Query(IEnumerable predicates) { foreach (Predicate predicate in predicates) { Predicates.Add(predicate); } } public Query(params Predicate[] predicates) { foreach (Predicate predicate in predicates) { Predicates.Add(predicate); } } public IEnumerable GetPredicates(QueryField queryField) { return Predicates.Where((x) => x.QueryField == queryField); } public virtual IEnumerable Search(OODB oodb) { Descriptor descriptor = oodb.GetDescriptor(); HashSet predicateFields = new HashSet(); 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 myresults = searchIndex.Query(predicate); if (results == null) { results = myresults.ToArray(); } else { results = results.Intersect(myresults).ToArray(); } } } return results.Select((id)=>oodb.Load(id)); } } public class AlternativesQuery : Query where T:Persistent { public HashSet> Alternatives = new HashSet>(); public AlternativesQuery(params Query[] queries) { foreach (Query alternative in queries) Alternatives.Add(alternative); } public override AlternativesQuery Or(Query alternativeQuery) { Alternatives.Add(alternativeQuery); return this; } public override AlternativesQuery Or(params Predicate[] predicates) { Alternatives.Add(new Query(predicates)); return this; } public override IEnumerable Search(OODB oodb) { return Alternatives.SelectMany((alternative) => alternative.Search(oodb)).Distinct(); } } }