private async Task <TreeNodeInfo> getNodeByPathSegment(TreePtr tree, GDID gParent, string pathSegment, DateTime asOfUtc, ICacheParams caching) { if (gParent.IsZero) { gParent = Constraints.G_VERY_ROOT_NODE; } var tblCache = s_CacheTableName[tree]; var keyCache = nameof(getNodeByPathSegment) + gParent.ToHexString() + (pathSegment ?? string.Empty) + asOfUtc.Ticks; var node = await m_Data.Cache.FetchThroughAsync( keyCache, tblCache, caching, async key => { var qry = new Query <TreeNodeInfo>("Tree.GetNodeInfo") { new Query.Param("tree", tree), new Query.Param("gparent", gParent), new Query.Param("psegment", pathSegment), new Query.Param("asof", asOfUtc) }; return(await m_Data.TreeLoadDocAsync(tree, qry)); } ).ConfigureAwait(false); return(node); }
/// <inheritdoc/> public async Task PurgeAsync(Atom idForest, Atom idTree) { idForest.HasRequiredValue(nameof(idForest)); idTree.HasRequiredValue(nameof(idForest)); App.Authorize(TreePurgePermission.Instance); var tree = new TreePtr(idForest, idTree); var qry = new Query <Doc>("Tree.Purge"); await m_Data.TreeExecuteAsync(tree, qry); }
private void purgeCacheTables(TreePtr tree) { var tname = s_CacheTableName[tree]; var tbl = m_Data.Cache.Tables[tname]; if (tbl == null) { return; } tbl.Purge(); }
public static async Task <TDoc> treeExecuteAsync <TDoc>(this IForestDataSource forestData, TreePtr tree, Query <TDoc> qry) where TDoc : Doc { var doc = await forestData.GetCrudData(tree).ExecuteAsync(qry).ConfigureAwait(false); if (doc == null) { return(null); } var result = doc.CastTo <TDoc>($"Query returned value of type `{doc.GetType().DisplayNameWithExpandedGenericArgs()}`"); return(result); }
/// <summary> /// Gets ICrudDataStore context for Corporate Area /// </summary> public static ICrudDataStore GetCrudData(this IForestDataSource forestData, TreePtr tree) { var tds = forestData.NonNull(nameof(forestData)).TryGetTreeDataStore(tree.IdForest, tree.IdTree); if (tds == null) { var tnmsg = "Forest tree `{0}` is not found".Args(tree); throw new ValidationException(tnmsg) { HttpStatusCode = 404, HttpStatusDescription = tnmsg }; } return((tds as ICrudDataStore).NonNull(DATA_STORE_CLAUSE)); }
private async Task <TreeNodeInfo> getNodeByTreePath(TreePtr tree, TreePath path, DateTime asOfUtc, ICacheParams caching) { var tblCache = s_CacheTableName[tree]; var keyCache = nameof(getNodeByTreePath) + path + asOfUtc.Ticks; var result = await m_Data.Cache.FetchThroughAsync( keyCache, tblCache, caching, async key => { TreeNodeInfo nodeParent = null; TreeNodeInfo node = null; for (var i = -1; i < path.Count; i++) //going from LEFT to RIGHT { var segment = i < 0 ? Constraints.VERY_ROOT_PATH_SEGMENT : path[i]; node = await getNodeByPathSegment(tree, nodeParent == null ? GDID.ZERO : nodeParent.Gdid, segment, asOfUtc, caching).ConfigureAwait(false); if (node == null) { return(null); // deleted } //Config chain inheritance pattern if (nodeParent == null) { node.EffectiveConfig = new ConfigVector(node.LevelConfig.Content);//Copy node.FullPath = Constraints.VERY_ROOT_PATH_SEGMENT; } else { var confHere = node.LevelConfig.Node.NonEmpty(nameof(node.LevelConfig)); var confParent = nodeParent.EffectiveConfig.Node.NonEmpty(nameof(nodeParent.EffectiveConfig)); var confResult = new MemoryConfiguration() { Application = this.App }; confResult.CreateFromNode(confParent); //inherit confResult.Root.OverrideBy(confHere); //override node.EffectiveConfig = new ConfigVector(confResult.Root); node.FullPath = TreePath.Join(nodeParent.FullPath, node.PathSegment); } nodeParent = node; App.Authorize(new TreePermission(TreeAccessLevel.Read, node.FullPathId)); } return(node); }).ConfigureAwait(false); return(result); }
private async Task <IEnumerable <TreeNodeHeader> > getChildNodeListByGdid(TreePtr tree, GDID gdidAddress, DateTime asOfUtc, ICacheParams caching) { var tblCache = s_CacheTableName[tree]; var keyCache = nameof(getChildNodeListByGdid) + gdidAddress.ToHexString() + asOfUtc.Ticks; var nodes = await m_Data.Cache.FetchThroughAsync( keyCache, tblCache, caching, async key => { var qry = new Query <TreeNodeHeader>("Tree.GetChildNodeList") { new Query.Param("tree", tree), new Query.Param("gparent", gdidAddress), new Query.Param("asof", asOfUtc) }; return(await m_Data.TreeLoadEnumerableAsync(tree, qry)); } ).ConfigureAwait(false); return(nodes); }
/// <inheritdoc/> public async Task <ChangeResult> SaveNodeAsync(TreeNode node) { node.NonNull(nameof(node)); var tree = new TreePtr(node.Forest, node.Tree); tree.IsAssigned.IsTrue("Assigned Tree"); App.Authorize(new TreePermission(TreeAccessLevel.Setup, node.Id)); var qry = new Query <EntityChangeInfo>("Tree.SaveNode") { new Query.Param("n", node) }; //1. Update database var change = await m_Data.TreeExecuteAsync(tree, qry); //purge cache for that tree purgeCacheTables(new TreePtr(node.Forest, node.Tree)); #warning Add shim for EVENT NOTIFICATION system return(new ChangeResult(ChangeResult.ChangeType.Processed, 1, "Saved", change)); }
private async Task <IEnumerable <TreeNodeHeader> > getChildNodeListByTreePath(TreePtr tree, TreePath pathAddress, DateTime asOfUtc, ICacheParams caching) { var nodeParent = await getNodeByTreePath(tree, pathAddress, asOfUtc, caching).ConfigureAwait(false); if (nodeParent == null) { return(null); } var result = await getChildNodeListByGdid(tree, nodeParent.Gdid, asOfUtc, caching); return(result); }
private async Task <TreeNodeInfo> getNodeByGdid(HashSet <GDID> graph, TreePtr tree, GDID gNode, DateTime asOfUtc, ICacheParams caching) { var tblCache = s_CacheTableName[tree]; var keyCache = nameof(getNodeByGdid) + gNode.ToHexString() + asOfUtc.Ticks; var result = await m_Data.Cache.FetchThroughAsync( keyCache, tblCache, caching, async key => { if (!graph.Add(gNode)) { //circular reference var err = new ConfigException("Circular reference in config tree = `{0}`, gnode = `{1}`, asof = `{2}`".Args(tree, gNode, asOfUtc)); WriteLogFromHere(Log.MessageType.CatastrophicError, err.Message, err, pars: new { tree = tree.ToString(), gnode = gNode, asof = asOfUtc }.ToJson()); throw err; } //1 - fetch THIS level - rightmost part of the tree var qry = new Query <TreeNodeInfo>("Tree.GetNodeInfoByGdid") { new Query.Param("tree", tree), new Query.Param("gdid", gNode), new Query.Param("asof", asOfUtc) }; var node = await m_Data.TreeLoadDocAsync(tree, qry); if (node == null) { return(null); } //2 - if IAM ROOT, there is no parent for root node.EffectiveConfig = new ConfigVector(node.LevelConfig.Content);//Copy node.FullPath = Constraints.VERY_ROOT_PATH_SEGMENT; if (node.Gdid == Constraints.G_VERY_ROOT_NODE) { return(node); } //3 - Fetch parent of THIS TreeNodeInfo nodeParent = await getNodeByGdid(graph, tree, node.G_Parent, asOfUtc, caching).ConfigureAwait(false); if (nodeParent == null) { return(null); } //4 - calculate effective config var cfgNode = node.LevelConfig.Node.NonEmpty(nameof(node.LevelConfig)); var cfgParent = nodeParent.EffectiveConfig.Node.NonEmpty(nameof(nodeParent.EffectiveConfig)); var confResult = new MemoryConfiguration() { Application = this.App }; confResult.CreateFromNode(cfgParent); //inherit confResult.Root.OverrideBy(cfgNode); //override node.EffectiveConfig.Node = confResult.Root; node.FullPath = TreePath.Join(nodeParent.FullPath, node.PathSegment); //the security check is done post factum AFTER tree node full path is known return(node); } ).ConfigureAwait(false); if (result == null) { return(null); } App.Authorize(new TreePermission(TreeAccessLevel.Read, result.FullPathId)); return(result); }
/// <summary> /// Extension which executes a query in tree data context and does not fetch any result /// </summary> public static ConfiguredTaskAwaitable <TDoc> TreeExecuteAsync <TDoc>(this IForestDataSource forestData, TreePtr tree, Query <TDoc> qry) where TDoc : Doc => forestData.treeExecuteAsync(tree, qry).ConfigureAwait(false);
/// <summary> /// Extension which loads a document returned by query executed in tree data context /// </summary> public static ConfiguredTaskAwaitable <TDoc> TreeLoadDocAsync <TDoc>(this IForestDataSource forestData, TreePtr tree, Query <TDoc> qry) where TDoc : Doc => forestData.GetCrudData(tree).LoadDocAsync(qry).ConfigureAwait(false);