diff --git a/Esiur.Stores.EntityCore/EntityStore.cs b/Esiur.Stores.EntityCore/EntityStore.cs index 580bb39..2d119d2 100644 --- a/Esiur.Stores.EntityCore/EntityStore.cs +++ b/Esiur.Stores.EntityCore/EntityStore.cs @@ -127,7 +127,7 @@ public class EntityStore : IStore public IResource GetById(Type type, object id) { if (!initialized) - throw new Exception("Store not initalized. Make sure the Warehouse is open."); + throw new Exception("Store is not initialized. Make sure the Warehouse is open."); lock (DBLock) { diff --git a/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs b/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs index 408c533..0bd7278 100644 --- a/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs +++ b/Esiur.Stores.EntityCore/EsiurExtensionOptions.cs @@ -35,6 +35,7 @@ using Microsoft.EntityFrameworkCore.Metadata; using System.Reflection; using Esiur.Proxy; using Microsoft.EntityFrameworkCore; +using Esiur.Resource; namespace Esiur.Stores.EntityCore; @@ -50,13 +51,15 @@ public class EsiurExtensionOptions : IDbContextOptionsExtension - private DbContextOptionsExtensionInfo _info; + DbContextOptionsExtensionInfo _info; EntityStore _store; + Warehouse _warehouse; public DbContextOptionsExtensionInfo Info => _info; public EntityStore Store => _store; + public Warehouse Warehouse => _warehouse; public void ApplyServices(IServiceCollection services) { @@ -84,6 +87,7 @@ public class EsiurExtensionOptions : IDbContextOptionsExtension { _info = new ExtensionInfo(this); _store = store; + _warehouse = store.Instance.Warehouse; } diff --git a/Esiur.Stores.EntityCore/EsiurExtensions.cs b/Esiur.Stores.EntityCore/EsiurExtensions.cs index cdee63d..87720ed 100644 --- a/Esiur.Stores.EntityCore/EsiurExtensions.cs +++ b/Esiur.Stores.EntityCore/EsiurExtensions.cs @@ -57,7 +57,8 @@ public static class EsiurExtensions public static async AsyncReply AddResourceAsync(this DbSet dbSet, T resource) where T : class, IResource { - var store = dbSet.GetInfrastructure().GetService().FindExtension().Store; + var options = dbSet.GetInfrastructure().GetService().FindExtension(); + var store = options.Store; if (store == null) throw new Exception("Store not set, please call 'UseEsiur' on your DbContextOptionsBuilder."); @@ -89,7 +90,6 @@ public static class EsiurExtensions foreach (var p in ps) { - var mi = resType.GetMember(p.Key, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance) .FirstOrDefault(); @@ -131,7 +131,7 @@ public static class EsiurExtensions var id = store.TypesByType[typeof(T)].PrimaryKey.GetValue(resource); - await Warehouse.Put(id.ToString(), res, store, null, null, 0, manager); + await options.Warehouse.Put(id.ToString(), res, store, null, 0, manager); return (T)res; } diff --git a/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs b/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs index 5762947..568fc6f 100644 --- a/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs +++ b/Esiur.Stores.EntityCore/EsiurProxyRewrite.cs @@ -69,11 +69,10 @@ public class EsiurProxyRewrite : IModelFinalizingConvention if (Codec.ImplementsInterface(entityType.ClrType, typeof(IResource))) { // check if the object exists - var obj = Warehouse.New(entityType.ClrType).Wait() as IResource; + var obj = options.Warehouse.CreateInstance(entityType.ClrType) as IResource; options.Store.TypesByType[entityType.ClrType].PrimaryKey.SetValue(obj, id); - Warehouse.Put(id.ToString(), obj, options.Store, null, null, 0, manager).Wait(); + options.Warehouse.Put(id.ToString(), obj, options.Store, null, 0, manager).Wait(); return obj; - } else { diff --git a/Esiur.Stores.MongoDB/MongoDBStore.cs b/Esiur.Stores.MongoDB/MongoDBStore.cs index fd16229..9fed634 100644 --- a/Esiur.Stores.MongoDB/MongoDBStore.cs +++ b/Esiur.Stores.MongoDB/MongoDBStore.cs @@ -110,7 +110,7 @@ public class MongoDBStore : IStore } [Export] - public bool Remove(IResource resource) + public AsyncReply Remove(IResource resource) { var objectId = resource.Instance.Variables["objectId"].ToString(); var filter = Builders.Filter.Eq("_id", new BsonObjectId(new ObjectId(objectId))); @@ -125,7 +125,7 @@ public class MongoDBStore : IStore Instance.Modified("Count"); - return true; + return new AsyncReply(true); } async AsyncReply Fetch(string id) where T : IResource @@ -159,7 +159,7 @@ public class MongoDBStore : IStore resources.Add(id, new WeakReference(resource)); //@TODO this causes store.put to be invoked, need fix - await Warehouse.Put(document["name"].AsString, resource, this); + await Instance.Warehouse.Put(document["name"].AsString, resource); var parents = document["parents"].AsBsonArray; @@ -887,23 +887,52 @@ public class MongoDBStore : IStore throw new NotImplementedException(); } - AsyncReply IStore.Remove(IResource resource) + + + + public AsyncReply Move(IResource resource, string newPath) { throw new NotImplementedException(); } + + public AsyncBag Parents(IResource resource, string name) where T : IResource + { + + if (resource == this) + { + return new AsyncBag(null); + } + else + { + var parents = (string[])resource.Instance.Variables["parents"]; + + if (parents == null) + { + return new AsyncBag(null); + } + + var rt = new AsyncBag(); + + + + foreach (var parent in parents) + { + var r = Instance.Warehouse.Get(parent); + if (r is AsyncReply) + rt.Add(r);// (AsyncReply)r); + } + + + rt.Seal(); + + + return rt; + } + } + public AsyncReply Remove(string path) { throw new NotImplementedException(); } - - public AsyncReply Move(IResource resource, string newPath) - { - throw new NotImplementedException(); - } - - public AsyncReply Parent(IResource resource, string name) where T : IResource - { - throw new NotImplementedException(); - } } diff --git a/Esiur.Stores.MongoDB/MongoDBStoreGeneric.cs b/Esiur.Stores.MongoDB/MongoDBStoreGeneric.cs index 9815d44..ec5e96b 100644 --- a/Esiur.Stores.MongoDB/MongoDBStoreGeneric.cs +++ b/Esiur.Stores.MongoDB/MongoDBStoreGeneric.cs @@ -38,7 +38,8 @@ namespace Esiur.Stores.MongoDB [Export] public async AsyncReply New(string name = null, object properties = null) { - var resource = await Warehouse.New(name, this, null, null, null, properties); + var resource = Instance.Warehouse.CreateInstance(properties); + await Instance.Warehouse.Put(name, resource, this, null, 0); resource.Instance.Managers.AddRange(this.Instance.Managers.ToArray()); return resource; } diff --git a/Esiur/Resource/Instance.cs b/Esiur/Resource/Instance.cs index bb59dd6..95df488 100644 --- a/Esiur/Resource/Instance.cs +++ b/Esiur/Resource/Instance.cs @@ -782,15 +782,15 @@ public class Instance return new AsyncBag(null); } - public AsyncReply Parent(string name = null) where T : IResource + public AsyncBag Parents(string name = null) where T : IResource { IResource res; if (this.resource.TryGetTarget(out res)) { - return store.Parent(res, name); + return store.Parents(res, name); } else - return new AsyncReply(default(T)); + return new AsyncBag(default(T[])); } /* diff --git a/Esiur/Resource/Warehouse.cs b/Esiur/Resource/Warehouse.cs index 9a62672..581526c 100644 --- a/Esiur/Resource/Warehouse.cs +++ b/Esiur/Resource/Warehouse.cs @@ -272,7 +272,7 @@ public class Warehouse if (p[0] == store.Instance.Name) { if (p.Length == 1) - return store; + return store; var res = await store.Get(String.Join("/", p.Skip(1).ToArray())); if (res != null) @@ -340,64 +340,56 @@ public class Warehouse /// Resource instance. /// IStore that manages the resource. Can be null if the resource is a store. /// Parent resource. if not presented the store becomes the parent for the resource. - public async AsyncReply Put(string path, T resource, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource + public async AsyncReply Put(string instanceName, T resource, IStore store, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource { if (resource.Instance != null) throw new Exception("Resource has a store."); - var location = path.TrimStart('/').Split('/'); - - IResource parent = null; - IStore store = null; - var instanceName = location.Last(); - - if (location.Length > 1) - { - parent = await Get(string.Join("/", path.Take(path.Length - 1))); - - if (parent == null) - throw new Exception("Can't find parent"); - - store = parent.Instance.Store; - } var resourceReference = new WeakReference(resource); + + if (resource is IStore && store == null) + store = (IStore)resource; + if (store == null) - { - // assign parent's store as a store - if (parent != null) - { - // assign parent as a store - if (parent is IStore) - { - store = (IStore)parent; - List> list; - if (stores.TryGetValue(store, out list)) - lock (((ICollection)list).SyncRoot) - list.Add(resourceReference); - //stores[store].Add(resourceReference); - } - else - { - store = parent.Instance.Store; + throw new Exception("Resource store is not set."); - List> list; - if (stores.TryGetValue(store, out list)) - lock (((ICollection)list).SyncRoot) - list.Add(resourceReference); - } - } - // assign self as a store (root store) - else if (resource is IStore) - { - store = (IStore)resource; - } - else - throw new Exception("Can't find a store for the resource."); - } + //if (store == null) + //{ + // // assign parent's store as a store + // if (parent != null) + // { + // // assign parent as a store + // if (parent is IStore) + // { + // store = (IStore)parent; + // List> list; + // if (stores.TryGetValue(store, out list)) + // lock (((ICollection)list).SyncRoot) + // list.Add(resourceReference); + // //stores[store].Add(resourceReference); + // } + // else + // { + // store = parent.Instance.Store; - resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, customTemplate, age); + // List> list; + // if (stores.TryGetValue(store, out list)) + // lock (((ICollection)list).SyncRoot) + // list.Add(resourceReference); + // } + // } + // // assign self as a store (root store) + // else if (resource is IStore) + // { + // store = (IStore)resource; + // } + // else + // throw new Exception("Can't find a store for the resource."); + //} + + resource.Instance = new Instance(this, resourceCounter++, instanceName, resource, store, customTemplate, age); if (attributes != null) if (attributes is Map attrs) @@ -408,8 +400,8 @@ public class Warehouse if (manager != null) resource.Instance.Managers.Add(manager); - if (store == parent) - parent = null; + //if (store == parent) + // parent = null; try @@ -451,11 +443,50 @@ public class Warehouse } return resource; + } - public async AsyncReply New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null) + /// + /// Put a resource in the warehouse. + /// + /// Resource name. + /// Resource instance. + /// IStore that manages the resource. Can be null if the resource is a store. + /// Parent resource. if not presented the store becomes the parent for the resource. + public async AsyncReply Put(string path, T resource, TypeTemplate customTemplate = null, ulong age = 0, IPermissionsManager manager = null, object attributes = null) where T : IResource { + if (resource.Instance != null) + throw new Exception("Resource has a store."); + var location = path.TrimStart('/').Split('/'); + + IResource parent = null; + + var instanceName = location.Last(); + + if (location.Length <= 1 && !(resource is IStore)) + throw new Exception("Can't find the store."); + else if (location.Length == 1) + return await Put(path, resource, null, customTemplate, age, manager, attributes); + else + { + // get parent + parent = await Get(string.Join("/", location.Take(location.Length - 1))); + + if (parent == null) + throw new Exception("Can't find parent"); + + return await Put(instanceName, resource, parent.Instance.Store, customTemplate, age, manager, attributes); + } + } + + public T CreateInstance(object properties = null) + { + return (T)CreateInstance(typeof(T), properties); + } + + public IResource CreateInstance(Type type, object properties = null) + { type = ResourceProxy.GetProxy(type); var res = Activator.CreateInstance(type) as IResource; @@ -466,7 +497,7 @@ public class Warehouse if (properties is Map map) { var template = GetTemplateByType(type); - foreach(var kvp in map) + foreach (var kvp in map) template.GetPropertyTemplateByIndex(kvp.Key).PropertyInfo.SetValue(res, kvp.Value); } else @@ -509,6 +540,12 @@ public class Warehouse } } + return res; + } + + public async AsyncReply New(Type type, string path, IPermissionsManager manager = null, object attributes = null, object properties = null) + { + var res = CreateInstance(type, properties); return await Put(path, res, null, 0, manager, attributes); }