using ln.types.btree; using System.Collections.Generic; using System; using ln.types.odb.ng.index; using System.Linq; using System.Collections; using ln.types.odb.ng.storage; using ln.types.odb.ng.mappings; using ln.objects.catalog; namespace ln.types.odb.ng { public partial class Mapper { BTree forwardCache = new BTree(); Dictionary reverseCache = new Dictionary(); public IEnumerable Load() => Load(typeof(T),false).Cast(); public IEnumerable Load(bool refresh) => Load(typeof(T),refresh).Cast(); public IEnumerable Load(Type type) => Load(type, false); public IEnumerable Load(Type type,bool refresh) { return new MappedObjectEnumeration(this, type, GetDocumentIDs(type),refresh); } public object[] LoadArray(Type type) => LoadArray(type, false); public object[] LoadArray(Type type, bool refresh) { MappedObjectEnumeration mappedObjectEnumeration = new MappedObjectEnumeration(this, type, GetDocumentIDs(type), refresh); object[] objects = new object[mappedObjectEnumeration.Count]; int n = 0; foreach (object o in mappedObjectEnumeration) objects[n++] = o; return objects; } public T Load(Guid documentID) => (T)Load(typeof(T), documentID, false); public T Load(Guid documentID,bool refresh) => (T)Load(typeof(T), documentID, refresh); public object Load(Type type, Guid documentID) => Load(type, documentID, false); public object Load(Type type, Guid documentID,bool refresh) { lock (this) { if (forwardCache.ContainsKey(documentID)) { CachedObject cachedObject = forwardCache[documentID]; if (refresh) Refresh(type, cachedObject.Instance); return cachedObject.Instance; } else { IStorage storage = StorageContainer.GetStorage(type.FullName); Document document = storage.Load(documentID); object instance = ObjectMapping.UnmapValue(this, document); CachedObject cachedObject = new CachedObject(document, instance); forwardCache.Add(cachedObject.Document.ID, cachedObject); reverseCache.Add(cachedObject.Instance, cachedObject); return cachedObject.Instance; } } } public IEnumerable Load(Query query) => Load(typeof(T), query, false).Cast(); public IEnumerable Load(Query query,bool refresh) => Load(typeof(T), query, refresh).Cast(); public IEnumerable Load(Type type, Query query) => Load(type, query, false); public IEnumerable Load(Type type,Query query,bool refresh) { IEnumerable matchedIDs = GetDocumentIDs(type,query); return new MappedObjectEnumeration(this, type, matchedIDs,refresh); } public bool Refresh(T instance) => Refresh(typeof(T), instance); public bool Refresh(Type type,object instance) { if (!reverseCache.TryGetValue(instance, out CachedObject cachedObject)) return false; IStorage storage = StorageContainer.GetStorage(type.FullName); if (storage.Refresh(cachedObject.Document)) { (GetMapping(type) as ClassMapping).Apply(this,cachedObject.Document,cachedObject.Instance); return true; } return false; } public void Save(T instance) => Save(typeof(T), instance); public void Save(Type type, object instance) { lock (this) { IStorage storage = GetStorage(type); CachedObject cachedObject; Document document; if (reverseCache.ContainsKey(instance)) { cachedObject = reverseCache[instance]; document = (GetMapping(type) as mappings.ClassMapping).MapDocument(this, cachedObject.Document.ID, instance); storage.Save(document); cachedObject.Document = document; } else { document = (GetMapping(type) as mappings.ClassMapping).MapDocument(this, Guid.NewGuid(), instance) as Document; cachedObject = new CachedObject(document, instance); storage.Save(document); forwardCache.Add(cachedObject.Document.ID, cachedObject); reverseCache.Add(instance, cachedObject); } } } public void Delete(T instance) => Delete(typeof(T),instance); public void Delete(Type type,object instance) { lock (this) { if (reverseCache.ContainsKey(instance)) { CachedObject cachedObject = reverseCache[instance]; reverseCache.Remove(instance); forwardCache.Remove(cachedObject.Document.ID); GetStorage(type).Delete(cachedObject.Document.ID); } } } public void Delete(Guid documentID) => Delete(typeof(T), documentID); public void Delete(Type type, Guid documentID) { lock (this) { if (forwardCache.ContainsKey(documentID)) { CachedObject cachedObject = forwardCache[documentID]; reverseCache.Remove(cachedObject.Instance); forwardCache.Remove(cachedObject.Document.ID); } GetStorage(type).Delete(documentID); } } public IEnumerable GetDocumentIDs() => GetDocumentIDs(typeof(T)); public IEnumerable GetDocumentIDs(Type type) { IStorage storage = StorageContainer.GetStorage(type.FullName); return storage.GetDocumentIDs(); } public IEnumerable GetDocumentIDs(string path, Predicate predicate) => GetDocumentIDs(typeof(T), path, predicate); public IEnumerable GetDocumentIDs(Type type, string path, Predicate predicate) { IStorage storage = StorageContainer.GetStorage(type.FullName); return storage.GetDocumentIDs(path,predicate); } public IEnumerable GetDocumentIDs(Query query) => GetDocumentIDs(typeof(T), query); public IEnumerable GetDocumentIDs(Type type,Query query) { IStorage storage = StorageContainer.GetStorage(type.FullName); return query.Execute(storage); } public void EnsureIndex(string path) => EnsureIndex(typeof(T), path); public void EnsureIndex(Type type,string path) { path = IndexPath.TranslatePropertyPath(type, path); IStorage storage = StorageContainer.GetStorage(type.FullName); storage.EnsureIndex(path); } struct CachedObject { public object Instance; public Document Document; public CachedObject(Document document, object instance) { Document = document; Instance = instance; } } class MappedObjectEnumeration : IEnumerable { Mapper mapper; Type type; IEnumerable documentIDs; bool refresh; public int Count => documentIDs.Count(); public MappedObjectEnumeration(Mapper mapper,Type type,IEnumerable documentIDs,bool refresh) { this.mapper = mapper; this.type = type; this.documentIDs = documentIDs; this.refresh = refresh; } public IEnumerator GetEnumerator() { foreach (Guid documentID in documentIDs) yield return mapper.Load(type, documentID, refresh); } } } }