GraphView.TranslateMatchClauseVisitor.ConstructGraph C# (CSharp) Méthode

ConstructGraph() private méthode

Constructs the graph pattern specified by the MATCH clause. The graph pattern may consist of multiple fully-connected sub-graphs.
private ConstructGraph ( GraphView.WSelectQueryBlock query ) : MatchGraph
query GraphView.WSelectQueryBlock The SELECT query block
Résultat MatchGraph
        private MatchGraph ConstructGraph(WSelectQueryBlock query)
        {
            if (query == null || query.MatchClause == null)
                return null;

            var columnsOfNodeTables = _graphMetaData.ColumnsOfNodeTables;
            var nodeViewMapping = _graphMetaData.NodeViewMapping;
            var unionFind = new UnionFind();
            var edgeColumnToAliasesDict = new Dictionary<string, List<string>>(StringComparer.OrdinalIgnoreCase);
            var pathDictionary = new Dictionary<string, MatchPath>(StringComparer.OrdinalIgnoreCase);
            var reversedEdgeDict = new Dictionary<string, MatchEdge>();
            var matchClause = query.MatchClause;
            var nodes = new Dictionary<string, MatchNode>(StringComparer.OrdinalIgnoreCase);
            var connectedSubGraphs = new List<ConnectedComponent>();
            var subGrpahMap = new Dictionary<string, ConnectedComponent>(StringComparer.OrdinalIgnoreCase);
            var parent = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            unionFind.Parent = parent;

            // Constructs the graph pattern specified by the path expressions in the MATCH clause
            foreach (var path in matchClause.Paths)
            {
                var index = 0;
                MatchEdge preEdge = null;
                for (var count = path.PathEdgeList.Count; index < count; ++index)
                {
                    var currentNodeTableRef = path.PathEdgeList[index].Item1;
                    var currentEdgeColumnRef = path.PathEdgeList[index].Item2;
                    var currentNodeExposedName = currentNodeTableRef.BaseIdentifier.Value;
                    var nextNodeTableRef = index != count - 1
                        ? path.PathEdgeList[index + 1].Item1
                        : path.Tail;
                    var nextNodeExposedName = nextNodeTableRef.BaseIdentifier.Value;
                    var patternNode = nodes.GetOrCreate(currentNodeExposedName);
                    if (patternNode.NodeAlias == null)
                    {
                        patternNode.NodeAlias = currentNodeExposedName;
                        patternNode.Neighbors = new List<MatchEdge>();
                        patternNode.External = false;
                        var nodeTable = _context[currentNodeExposedName] as WNamedTableReference;
                        if (nodeTable != null)
                        {
                            patternNode.NodeTableObjectName = nodeTable.TableObjectName;
                            if (patternNode.NodeTableObjectName.SchemaIdentifier == null)
                                patternNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                        }
                    }

                    Identifier edgeIdentifier = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last();
                    string schema = patternNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                    string nodeTableName = patternNode.NodeTableObjectName.BaseIdentifier.Value;
                    string bindTableName =
                        _context.EdgeNodeBinding[
                            new Tuple<string, string>(nodeTableName.ToLower(), edgeIdentifier.Value.ToLower())].ToLower();
                    var bindNodeTableObjName = new WSchemaObjectName(
                        new Identifier {Value = schema},
                        new Identifier {Value = bindTableName}
                        );
                    var edgeColumn =
                        columnsOfNodeTables[
                            WNamedTableReference.SchemaNameToTuple(bindNodeTableObjName)][
                                currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value];
                    string edgeAlias = currentEdgeColumnRef.Alias;
                    //string revEdgeAlias = edgeAlias;
                    bool isReversed = path.IsReversed || edgeColumn.EdgeInfo.IsReversedEdge;
                    string currentRevEdgeName = null;

                    // get original edge name
                    var currentEdgeName = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().Value;
                    var originalSourceName = isReversed ?
                        (_context[nextNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value
                        : (_context[currentNodeExposedName] as WNamedTableReference).TableObjectName.BaseIdentifier.Value;

                    if (isReversed)
                    {
                        var i = currentEdgeName.IndexOf(originalSourceName, StringComparison.OrdinalIgnoreCase) +
                            originalSourceName.Length;
                        currentRevEdgeName = currentEdgeName.Substring(i + 1,
                            currentEdgeName.Length - "Reversed".Length - i - 1);
                    }
                    else
                    {
                        var srcTuple = WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName);
                        // [nodeView]-[edge]->[node/nodeView]
                        if (edgeColumn.Role == WNodeTableColumnRole.Edge && nodeViewMapping.ContainsKey(srcTuple))
                        {
                            var physicalNodeName =
                                _context.EdgeNodeBinding[new Tuple<string, string>(srcTuple.Item2, currentEdgeName.ToLower())];
                            currentRevEdgeName = physicalNodeName + "_" + currentEdgeName + "Reversed";
                        }
                        else
                        {
                            currentRevEdgeName = originalSourceName + "_" + currentEdgeName + "Reversed";
                        }
                    }

                    if (edgeAlias == null)
                    {
                        edgeAlias = !isReversed
                            ? string.Format("{0}_{1}_{2}", currentNodeExposedName, currentEdgeName, nextNodeExposedName)
                            : string.Format("{0}_{1}_{2}", nextNodeExposedName, currentRevEdgeName, currentNodeExposedName);

                        //when the current edge is a reversed edge, the key should still be the original edge name
                        //e.g.: TestDeleteEdgeWithTableAlias
                        var edgeNameKey = isReversed ? currentRevEdgeName : currentEdgeName;
                        if (edgeColumnToAliasesDict.ContainsKey(edgeNameKey))
                        {
                            edgeColumnToAliasesDict[edgeNameKey].Add(edgeAlias);
                        }
                        else
                        {
                            edgeColumnToAliasesDict.Add(edgeNameKey, new List<string> { edgeAlias });
                        }
                    }

                    MatchEdge edge, revEdge;
                    if (currentEdgeColumnRef.MinLength == 1 && currentEdgeColumnRef.MaxLength == 1)
                    {
                        var isEdgeView = edgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var hasRevEdge = edgeColumn.EdgeInfo.HasReversedEdge;
                        edge = new MatchEdge
                        {
                            IsEdgeView = isEdgeView,
                            IsReversedEdge = false,
                            HasReversedEdge = hasRevEdge,
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName = bindNodeTableObjName,
                        };
                        _context.AddEdgeReference(edge);

                        if (hasRevEdge)
                        {
                            revEdge = new MatchEdge
                            {
                                IsEdgeView = isEdgeView,
                                IsReversedEdge = true,
                                SinkNode = patternNode,
                                EdgeColumn = new WEdgeColumnReferenceExpression()
                                {
                                    ColumnType = currentEdgeColumnRef.ColumnType,
                                    Alias = currentEdgeColumnRef.Alias,
                                    MaxLength = currentEdgeColumnRef.MaxLength,
                                    MinLength = currentEdgeColumnRef.MinLength,
                                    AttributeValueDict = currentEdgeColumnRef.AttributeValueDict,
                                    MultiPartIdentifier = new WMultiPartIdentifier(new Identifier()
                                    {
                                        QuoteType = currentEdgeColumnRef.MultiPartIdentifier.Identifiers.Last().QuoteType,
                                        Value = currentRevEdgeName,
                                    }),
                                },
                                EdgeAlias = edgeAlias,
                                //EdgeAlias = revEdgeAlias,
                            };
                            reversedEdgeDict[edge.EdgeAlias] = revEdge;
                        }
                    }
                    else
                    {
                        MatchPath matchPath = new MatchPath
                        {
                            SourceNode = patternNode,
                            EdgeColumn = currentEdgeColumnRef,
                            EdgeAlias = edgeAlias,
                            BindNodeTableObjName =
                                new WSchemaObjectName(
                                    new Identifier {Value = schema},
                                    new Identifier {Value = bindTableName}
                                    ),
                            MinLength = currentEdgeColumnRef.MinLength,
                            MaxLength = currentEdgeColumnRef.MaxLength,
                            ReferencePathInfo = false,
                            AttributeValueDict = currentEdgeColumnRef.AttributeValueDict
                        };
                        _context.AddEdgeReference(matchPath);
                        pathDictionary[edgeAlias] = matchPath;
                        edge = matchPath;
                    }

                    if (preEdge != null)
                    {
                        preEdge.SinkNode = patternNode;
                        if (preEdge.HasReversedEdge)
                        {
                            //var preSourceNode = preEdge.SourceNode;
                            var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                            var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                            var preEdgeColumn =
                                columnsOfNodeTables[
                                    WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                        preEdgeColName];
                            var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                            var isNodeView =
                                _graphMetaData.NodeViewMapping.ContainsKey(
                                    WNamedTableReference.SchemaNameToTuple(patternNode.NodeTableObjectName));

                            reversedEdgeDict[preEdge.EdgeAlias].SourceNode = patternNode;
                            // [node/nodeView]-[edgeView]->[node/nodeView]
                            if (isEdgeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                            }
                            // [node/nodeView]-[edge]->[nodeView]
                            else if (!isEdgeView && isNodeView)
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = "dbo" },
                                    new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                    );
                            }
                            else
                            {
                                reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                    new Identifier { Value = schema },
                                    new Identifier { Value = bindTableName }
                                    );
                            }
                        }
                    }
                    preEdge = edge;

                    if (!parent.ContainsKey(currentNodeExposedName))
                        parent[currentNodeExposedName] = currentNodeExposedName;
                    if (!parent.ContainsKey(nextNodeExposedName))
                        parent[nextNodeExposedName] = nextNodeExposedName;

                    unionFind.Union(currentNodeExposedName, nextNodeExposedName);

                    patternNode.Neighbors.Add(edge);

                }
                var tailExposedName = path.Tail.BaseIdentifier.Value;
                var tailNode = nodes.GetOrCreate(tailExposedName);
                if (tailNode.NodeAlias == null)
                {
                    tailNode.NodeAlias = tailExposedName;
                    tailNode.Neighbors = new List<MatchEdge>();
                    var nodeTable = _context[tailExposedName] as WNamedTableReference;
                    if (nodeTable != null)
                    {
                        tailNode.NodeTableObjectName = nodeTable.TableObjectName;
                        if (tailNode.NodeTableObjectName.SchemaIdentifier == null)
                            tailNode.NodeTableObjectName.Identifiers.Insert(0, new Identifier {Value = "dbo"});
                    }
                }
                if (preEdge != null)
                {
                    preEdge.SinkNode = tailNode;
                    if (preEdge.HasReversedEdge)
                    {
                        var schema = tailNode.NodeTableObjectName.SchemaIdentifier.Value.ToLower();
                        var nodeTableName = tailNode.NodeTableObjectName.BaseIdentifier.Value;
                        //var preSourceNode = preEdge.SourceNode;
                        var preEdgeBindNodeTableObjName = preEdge.BindNodeTableObjName;
                        var preEdgeColName = preEdge.EdgeColumn.MultiPartIdentifier.Identifiers.Last().Value;
                        var preEdgeColumn =
                            columnsOfNodeTables[
                                WNamedTableReference.SchemaNameToTuple(preEdgeBindNodeTableObjName)][
                                    preEdgeColName];
                        var isEdgeView = preEdgeColumn.Role == WNodeTableColumnRole.EdgeView;
                        var isNodeView =
                            _graphMetaData.NodeViewMapping.ContainsKey(
                                WNamedTableReference.SchemaNameToTuple(tailNode.NodeTableObjectName));
                        reversedEdgeDict[preEdge.EdgeAlias].SourceNode = tailNode;
                        // [node/nodeView]-[edgeView]->[node/nodeView]
                        if (isEdgeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = preEdgeBindNodeTableObjName;
                        }
                        // [node/nodeView]-[edge]->[nodeView]
                        else if (!isEdgeView && isNodeView)
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = "dbo" },
                                new Identifier { Value = preEdgeColumn.EdgeInfo.SinkNodes.First() }
                                );
                        }
                        else
                        {
                            reversedEdgeDict[preEdge.EdgeAlias].BindNodeTableObjName = new WSchemaObjectName(
                                new Identifier { Value = schema },
                                new Identifier { Value = nodeTableName.ToLower() }
                                );
                        }
                    }
                }
            }

            // Puts nodes into subgraphs
            foreach (var node in nodes)
            {
                string root = unionFind.Find(node.Key);
                if (!subGrpahMap.ContainsKey(root))
                {
                    var subGraph = new ConnectedComponent();
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGrpahMap[root] = subGraph;
                    connectedSubGraphs.Add(subGraph);
                    subGraph.IsTailNode[node.Value] = false;
                }
                else
                {
                    var subGraph = subGrpahMap[root];
                    subGraph.Nodes[node.Key] = node.Value;
                    foreach (var edge in node.Value.Neighbors)
                    {
                        subGraph.Edges[edge.EdgeAlias] = edge;
                    }
                    subGraph.IsTailNode[node.Value] = false;
                }
            }

            var graph = new MatchGraph
            {
                ReversedEdgeDict = reversedEdgeDict,
                ConnectedSubGraphs = connectedSubGraphs,
                SourceNodeStatisticsDict = new Dictionary<Tuple<string, bool>, Statistics>(),
            };
            unionFind.Parent = null;

            // When an edge in the MATCH clause is not associated with an alias,
            // assigns to it a default alias: sourceAlias_EdgeColumnName_sinkAlias.
            // Also rewrites edge attributes anywhere in the query that can be bound to this default alias.
            var replaceTableRefVisitor = new ReplaceEdgeReferenceVisitor();
            replaceTableRefVisitor.Invoke(query, edgeColumnToAliasesDict);

            // Rematerializes node tables in the MATCH clause which are defined in the upper-level context
            // and join them with the upper-level table references.
            RematerilizeExtrenalNodeTableReference(query, nodes);

            // Transforms the path reference in the SELECT elements into a
            // scalar function to display path information.
            TransformPathInfoDisplaySelectElement(query, pathDictionary);

            return graph;
        }