using System; using System.Collections.Generic; using System.Collections; using System.Reflection; using System.Linq; using System.Runtime.InteropServices.ComTypes; using ln.objects.catalog; namespace ln.types.odb.ng.index { public abstract class IndexPath { public static IndexPath Build(Path path) { if (path.Element == null) return new FinalPath(path); if (path.Element.Equals("[]")) return new ListPath(); return new DocumentPath(); } public abstract IEnumerable GetIndeces(); public abstract bool Ensure(Path path); public abstract bool Indexed(Path path); public virtual void Replace(Guid documentID, ODBEntity value) { Remove(documentID); Add(documentID, value); } public abstract void Add(Guid documentID, ODBEntity value); public abstract void Remove(Guid documentID); public abstract IEnumerable GetDocumentIDs(Path path, Predicate predicate); public virtual IEnumerable GetDocumentIDs(string path, Predicate predicate) { return GetDocumentIDs(SplitPath(path), predicate); } public class DocumentPath : IndexPath { Dictionary children = new Dictionary(); public DocumentPath() { } public override IEnumerable GetDocumentIDs(Path path, Predicate predicate) { return children[path.Element].GetDocumentIDs(path.Next, predicate); } public override IEnumerable GetIndeces() { return children.Values.SelectMany((arg) => arg.GetIndeces()); } public override bool Indexed(Path path) { if (children.ContainsKey(path.Element)) return children[path.Element].Indexed(path.Next); return false; } public override void Remove(Guid documentID) { foreach (IndexPath next in children.Values) next.Remove(documentID); } public override void Add(Guid documentID, ODBEntity value) { foreach (string childName in children.Keys) { children[childName].Add(documentID, (value as Document)[childName]); } } public override void Replace(Guid documentID, ODBEntity value) { foreach (string childName in children.Keys) { children[childName].Replace(documentID, (value as Document)[childName]); } } public override bool Ensure(Path path) { bool added = false; if (!children.ContainsKey(path.Element)) { children.Add(path.Element, IndexPath.Build(path.Next)); added = true; } return children[path.Element].Ensure(path.Next) || added; } } class ListPath : IndexPath { IndexPath nextPath; public ListPath() { } public override IEnumerable GetIndeces() => nextPath.GetIndeces(); public override bool Ensure(Path path) { bool added = false; if (nextPath == null) { nextPath = IndexPath.Build(path.Next); added = true; } return nextPath.Ensure(path.Next) || added; } public override bool Indexed(Path path) { return nextPath.Indexed(path.Next); } public override IEnumerable GetDocumentIDs(Path path, Predicate predicate) { return nextPath.GetDocumentIDs(path.Next, predicate); } public override void Remove(Guid documentID) { nextPath.Remove(documentID); } public override void Add(Guid documentID, ODBEntity value) { if (!ODBNull.Instance.Equals(value)) foreach (ODBEntity v in ((ODBList)value)) { nextPath.Add(documentID, v); } } } class FinalPath : IndexPath { Path indexPath; Index index; public FinalPath(Path indexPath) { this.indexPath = indexPath; } public override IEnumerable GetIndeces() => new Index[] { index }; public override bool Indexed(Path path) => true; public override IEnumerable GetDocumentIDs(Path path, Predicate predicate) { return index.GetDocumentIDs(predicate); } public override void Remove(Guid documentID) { index.Remove(documentID); } public override void Add(Guid documentID, ODBEntity value) { index.Add(documentID, value); } public override void Replace(Guid documentID, ODBEntity value) { index.Replace(documentID, value); } public override bool Ensure(Path path) { if (path.Element != null) throw new NotSupportedException(); if (index == null) { index = new SimpleIndex(indexPath); return true; } return false; } } public static Path SplitPath(string path) { List pathTokens = new List(); foreach (string primaryToken in path.Split('.')) { string suffix = ""; string token = primaryToken; int i = token.IndexOf('['); if (i > 0) { suffix = token.Substring(i); token = token.Substring(0, i); } pathTokens.Add(token); string s = suffix; while (s.Length > 0) { if (s.StartsWith("[]", StringComparison.InvariantCulture)) { pathTokens.Add("[]"); s = s.Substring(2); } else { throw new NotSupportedException(); } } } return new Path(pathTokens.ToArray()); } public static string TranslatePropertyPath(Type elementType, string propPath) { String[] path = propPath.Split('.'); Type currentType = elementType; for (int n = 0; n < path.Length; n++) { string suffix = ""; string token = path[n]; int i = token.IndexOf('['); if (i > 0) { suffix = token.Substring(i); token = token.Substring(0, i); } FieldInfo fieldInfo = currentType.GetField(token, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (fieldInfo == null) { string backingFieldName = String.Format("<{0}>k__BackingField", token); PropertyInfo propertyInfo = currentType.GetProperty(token, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (propertyInfo != null) { fieldInfo = currentType.GetField(backingFieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); if (fieldInfo == null) throw new NotImplementedException("can't identify backing field for property"); } else { throw new ArgumentOutOfRangeException(nameof(path)); } } token = fieldInfo.Name; currentType = fieldInfo.FieldType; string s = suffix; while (s.Length > 0) { if (s.StartsWith("[]", StringComparison.InvariantCulture)) { if (currentType.IsArray) currentType = currentType.GetElementType(); else if (currentType.IsGenericType) currentType = currentType.GetGenericArguments()[0]; else throw new NotSupportedException(); s = s.Substring(2); } else { throw new NotSupportedException(); } } path[n] = String.Format("{0}{1}", token, suffix); } return String.Join(".", path); } } //class wait { // protected Index Index; // IndexPath NextIndexPath; // protected IndexPath() // {} // protected IndexPath(Index index) // { // Index = index; // } // public IndexPath(Index index, Queue path) // :this(index) // { // NextIndexPath = CreateNextIndexPath(path); // } // private IndexPath CreateNextIndexPath(Queue path) // { // if (path.Count == 0) // { // return new IndexUpdatePath(Index); // } // else // { // return new PropertyPath(propertyIndex, path); // } // } // public virtual void UpdateIndex(ODBDocument document) // { // propertyIndex.TryRemove(document.ID); // UpdateIndex(document, document); // } // public virtual void UpdateIndex(ODBDocument document, ODBValue element) // { // NextIndexPath.UpdateIndex(document, element); // } // public virtual IEnumerable Retrieve(ODBValue element) // { // return NextIndexPath.Retrieve(element); // } // class PropertyPath : IndexPath // { // string propertyName; // public PropertyPath(PropertyIndex propertyIndex,Queue path) // :base(propertyIndex) // { // propertyName = path.Dequeue(); // NextIndexPath = CreateNextIndexPath(path); // while (propertyName.EndsWith("[]",StringComparison.InvariantCulture)) // { // NextIndexPath = new EnumPath(propertyIndex, NextIndexPath); // propertyName = propertyName.Substring(0, propertyName.Length - 2); // } // } // public override void UpdateIndex(ODBDocument document, ODBValue element) // { // if (element is ODBDocument) // { // ODBDocument edoc = element as ODBDocument; // NextIndexPath.UpdateIndex(document, edoc[propertyName]); // } // } // public override IEnumerable Retrieve(ODBValue element) // { // if (element is ODBDocument) // { // ODBDocument edoc = element as ODBDocument; // return NextIndexPath.Retrieve(edoc[propertyName]); // } // return new ODBValue[0]; // } // } // class EnumPath : IndexPath // { // public EnumPath(PropertyIndex propertyIndex,IndexPath nextIndexPath) // : base(propertyIndex) // { // NextIndexPath = nextIndexPath; // } // public override void UpdateIndex(ODBDocument document, ODBValue element) // { // if (element is ODBList) // { // ODBList elist = element as ODBList; // foreach (ODBValue le in elist) // { // NextIndexPath.UpdateIndex(document, le); // } // } // } // public override IEnumerable Retrieve(ODBValue element) // { // if (element is ODBList) // { // ODBList elist = element as ODBList; // return elist.SelectMany(e => NextIndexPath.Retrieve(e)); // } // return new ODBValue[0]; // } // } // class IndexUpdatePath : IndexPath // { // public IndexUpdatePath(PropertyIndex propertyIndex) // : base(propertyIndex) // { // } // public override void UpdateIndex(ODBDocument document, ODBValue element) // { // propertyIndex.Add(element, document.ID); // } // public override IEnumerable Retrieve(ODBValue element) // { // return new ODBValue[] { element }; // } // } //} }