Exemple #1
0
 public JsonQuery(JsonQuery rhs)
 {
     this.SelectClause         = rhs.SelectClause;
     this.JoinClause           = rhs.JoinClause;
     this.WhereSearchCondition = rhs.WhereSearchCondition;
     this.Alias          = rhs.Alias;
     this.NodeProperties = rhs.NodeProperties;
     this.EdgeProperties = rhs.EdgeProperties;
 }
        internal JObject RetrieveDocumentById(string docId, string partition, GraphViewCommand command)
        {
            Debug.Assert(!string.IsNullOrEmpty(docId), "'docId' should not be null or empty");

            const string NODE_ALIAS = "doc";

            JsonQuery jsonQuery = new JsonQuery
            {
                NodeAlias = NODE_ALIAS
            };

            jsonQuery.AddSelectElement("*");

            jsonQuery.RawWhereClause = new WBooleanComparisonExpression
            {
                ComparisonType = BooleanComparisonType.Equals,
                FirstExpr      = new WColumnReferenceExpression(NODE_ALIAS, KW_DOC_ID),
                SecondExpr     = new WValueExpression(docId, true)
            };
            jsonQuery.FlatProperties.Add(KW_DOC_ID);


            if (partition != null)
            {
                Debug.Assert(this.PartitionPath != null);
                jsonQuery.FlatProperties.Add(partition);
                jsonQuery.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    // TODO: new type to represent this??
                    FirstExpr  = new WValueExpression($"{NODE_ALIAS}{this.GetPartitionPathIndexer()}", false),
                    SecondExpr = new WValueExpression(partition, true)
                }, BooleanBinaryExpressionType.And);
            }

            JObject result = this.CreateDatabasePortal().GetVertexDocument(jsonQuery);

            //
            // Save etag of the fetched document
            // No override!
            //
            if (result != null)
            {
                command.VertexCache.SaveCurrentEtagNoOverride(result);
            }

            return(result);
        }
        /// <summary>
        /// For every vertex in the vertexIdSet, retrieve their spilled edge documents to construct their forward or backward
        /// adjacency list.
        /// When connection.useReverseEdge is false, this method will retrieve all the forward edge documents whose sink
        /// is the target vertex to build a virtual reverse adjacency list.
        /// </summary>
        /// <param name="command"></param>
        /// <param name="edgeType"></param>
        /// <param name="vertexIdSet"></param>
        /// <param name="vertexPartitionKeySet"></param>
        public static void ConstructLazyAdjacencyList(
            GraphViewCommand command,
            EdgeType edgeType,
            HashSet <string> vertexIdSet,
            HashSet <string> vertexPartitionKeySet)
        {
            if (!vertexIdSet.Any())
            {
                return;
            }

            const string ALIAS = "edgeDoc";

            var queryBoth = new JsonQuery
            {
                EdgeAlias = ALIAS
            };

            queryBoth.AddSelectElement("*");
            queryBoth.RawWhereClause = new WInPredicate(new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_VERTEXID), vertexIdSet.ToList());
            queryBoth.FlatProperties.Add(KW_EDGEDOC_VERTEXID);

            if (vertexPartitionKeySet.Any())
            {
                // TODO: Refactor this.
                queryBoth.WhereConjunction(new WInPredicate(new WValueExpression($"{ALIAS}{command.Connection.GetPartitionPathIndexer()}"), vertexPartitionKeySet.ToList()),
                                           BooleanBinaryExpressionType.And);
            }
            if (edgeType == EdgeType.Outgoing)
            {
                queryBoth.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_ISREVERSE),
                    SecondExpr     = new WValueExpression("false")
                }, BooleanBinaryExpressionType.And);
                queryBoth.FlatProperties.Add(KW_EDGEDOC_ISREVERSE);
            }
            else if (edgeType == EdgeType.Incoming)
            {
                queryBoth.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(ALIAS, KW_EDGEDOC_ISREVERSE),
                    SecondExpr     = new WValueExpression("true")
                }, BooleanBinaryExpressionType.And);
                queryBoth.FlatProperties.Add(KW_EDGEDOC_ISREVERSE);
            }

//            var qqq = queryBoth.ToJsonServerString();

            List <JObject> edgeDocuments = command.Connection.CreateDatabasePortal().GetEdgeDocuments(queryBoth);

            // Dictionary<vertexId, Dictionary<edgeDocumentId, edgeDocument>>
            var edgeDict = new Dictionary <string, Dictionary <string, JObject> >();

            foreach (JObject edgeDocument in edgeDocuments)
            {
                // Save edgeDocument's etag if necessary
                command.VertexCache.SaveCurrentEtagNoOverride(edgeDocument);
            }

            EdgeDocumentHelper.FillEdgeDict(edgeDict, edgeDocuments);

            //
            // Use all edges whose sink is vertexId to construct a virtual reverse adjacency list of this vertex
            //
            if (!command.Connection.UseReverseEdges && edgeType.HasFlag(EdgeType.Incoming))
            {
                // TODO: old Version JsonQuery, delete it when you understand this query.
//                string selectClause = $"{{" +
//                               $"  \"{EdgeDocumentHelper.VirtualReverseEdgeObject}\": edge, " +
//                               $"  \"{KW_EDGE_SRCV}\": doc.{KW_DOC_ID}, " +
//                               $"  \"{KW_EDGE_SRCV_LABEL}\": doc.{KW_VERTEX_LABEL}," +
//                               (command.Connection.PartitionPath != null
//                                   ? $"  \"{KW_EDGE_SRCV_PARTITION}\": doc{command.Connection.GetPartitionPathIndexer()},"
//                                   : "") +
//                               $"  \"{KW_EDGEDOC_VERTEXID}\": doc.{KW_EDGEDOC_VERTEXID}," +
//                               $"  \"{KW_EDGEDOC_VERTEX_LABEL}\": doc.{KW_EDGEDOC_VERTEX_LABEL}" +
//                               $"}} AS {EdgeDocumentHelper.VirtualReverseEdge}";
//                string alise = "doc";
//                string joinClause = $"JOIN edge IN doc.{DocumentDBKeywords.KW_VERTEX_EDGE}";
//                string inClause = string.Join(", ", vertexIdSet.Select(vertexId => $"'{vertexId}'"));
//                string whereSearchCondition = $"edge.{KW_EDGE_SINKV} IN ({inClause})";

                const string NODE_ALISE_S  = "node";
                const string EDGE_ALISE_S  = "edge";
                var          queryReversed = new JsonQuery
                {
                    NodeAlias = NODE_ALISE_S,
                    EdgeAlias = EDGE_ALISE_S
                };
                // Construct select clause.
                List <WPrimaryExpression> selectList = new List <WPrimaryExpression>
                {
                    new WValueExpression($"{{  \"{EdgeDocumentHelper.VirtualReverseEdgeObject}\": "),
                    new WColumnReferenceExpression(EDGE_ALISE_S, "*"),
                    new WValueExpression($",  \"{KW_EDGE_SRCV}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_DOC_ID),
                    new WValueExpression($",  \"{KW_EDGE_SRCV_LABEL}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_VERTEX_LABEL),
                    new WValueExpression($",  \"{KW_EDGEDOC_VERTEXID}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_EDGEDOC_VERTEXID),
                    new WValueExpression($",  \"{KW_EDGEDOC_VERTEX_LABEL}\": "),
                    new WColumnReferenceExpression(NODE_ALISE_S, KW_EDGEDOC_VERTEX_LABEL),
                };
                if (command.Connection.PartitionPath != null)
                {
                    selectList.Add(new WValueExpression($",  \"{KW_EDGE_SRCV_PARTITION}\": "));
                    // TODO: hack operation, when meet columnName[0] = '[', the toDocDbString function will do something special.
                    selectList.Add(new WColumnReferenceExpression(NODE_ALISE_S, command.Connection.GetPartitionPathIndexer()));
                }
                selectList.Add(new WValueExpression("}"));
                queryReversed.AddSelectElement(EdgeDocumentHelper.VirtualReverseEdge, selectList);

                // Construct join clause
                queryReversed.JoinDictionary.Add(EDGE_ALISE_S, $"{NODE_ALISE_S}.{DocumentDBKeywords.KW_VERTEX_EDGE}");

                // construct where clause
                queryReversed.RawWhereClause = new WInPredicate(
                    new WColumnReferenceExpression(EDGE_ALISE_S, KW_EDGE_SINKV),
                    new List <string>(vertexIdSet));


                edgeDocuments = command.Connection.CreateDatabasePortal().GetEdgeDocuments(queryReversed);

                List <JObject> virtualReverseEdgeDocuments = EdgeDocumentHelper.ConstructVirtualReverseEdgeDocuments(edgeDocuments);

                EdgeDocumentHelper.FillEdgeDict(edgeDict, virtualReverseEdgeDocuments);
            }

            foreach (KeyValuePair <string, Dictionary <string, JObject> > pair in edgeDict)
            {
                string vertexId = pair.Key;
                Dictionary <string, JObject> edgeDocDict = pair.Value; // contains both in & out edges
                VertexField vertexField;
                command.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(edgeType, edgeDocDict);
                vertexIdSet.Remove(vertexId);
            }

            foreach (string vertexId in vertexIdSet)
            {
                VertexField vertexField;
                command.VertexCache.TryGetVertexField(vertexId, out vertexField);
                vertexField.ConstructSpilledOrVirtualAdjacencyListField(edgeType, new Dictionary <string, JObject>());
            }
        }
        /// <summary>
        /// Find incoming or outgoing edge by "srcId and edgeId"
        /// Output the edgeObject, as well as the edgeDocId (null for small-degree edges)
        /// </summary>
        /// <param name="command"></param>
        /// <param name="vertexObject"></param>
        /// <param name="srcVertexId"></param>
        /// <param name="edgeId"></param>
        /// <param name="isReverseEdge"></param>
        /// <param name="edgeObject"></param>
        /// <param name="edgeDocId"></param>
        public static void FindEdgeBySourceAndEdgeId(
            GraphViewCommand command,
            JObject vertexObject, string srcVertexId, string edgeId, bool isReverseEdge,
            out JObject edgeObject, out string edgeDocId)
        {
            if (!isReverseEdge)
            {
                Debug.Assert((string)vertexObject[KW_DOC_ID] == srcVertexId);
            }
            JToken edgeContainer = vertexObject[isReverseEdge ? KW_VERTEX_REV_EDGE : KW_VERTEX_EDGE];

            if (!IsSpilledVertex(vertexObject, isReverseEdge))
            {
                // for small-degree vertexes
                if (isReverseEdge)
                {
                    edgeObject = (from edgeObj in edgeContainer.Children <JObject>()
                                  where (string)edgeObj[KW_EDGE_SRCV] == srcVertexId
                                  where (string)edgeObj[KW_EDGE_ID] == edgeId
                                  select edgeObj
                                  ).FirstOrDefault();
                }
                else
                {
                    edgeObject = (from edgeObj in edgeContainer.Children <JObject>()
                                  where (string)edgeObj[KW_EDGE_ID] == edgeId
                                  select edgeObj
                                  ).FirstOrDefault();
                }
                edgeDocId = null;
            }
            else
            {
                // For large-degree vertices
                // Now the vertex document stores the last(latest) spilled edge document only.

                const string VERTEX_ALIAS    = "doc";
                const string EDGE_SELECT_TAG = "edge";
                var          jsonQuery       = new JsonQuery
                {
                    NodeAlias = VERTEX_ALIAS,
                    EdgeAlias = EDGE_SELECT_TAG
                };
                // SELECT doc.id, edge
                jsonQuery.AddSelectElement(VERTEX_ALIAS);
                jsonQuery.AddSelectElement(EDGE_SELECT_TAG);

                jsonQuery.JoinDictionary.Add(EDGE_SELECT_TAG, $"{VERTEX_ALIAS}.{KW_EDGEDOC_EDGE}");
                jsonQuery.EdgeProperties = new List <string>();
                jsonQuery.NodeProperties = new List <string>();
                jsonQuery.RawWhereClause = new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(VERTEX_ALIAS, KW_EDGEDOC_ISREVERSE),
                    SecondExpr     = new WValueExpression(isReverseEdge.ToString().ToLowerInvariant(), false)
                };
                jsonQuery.FlatProperties.Add(KW_EDGEDOC_ISREVERSE);

                jsonQuery.WhereConjunction(new WBooleanComparisonExpression
                {
                    ComparisonType = BooleanComparisonType.Equals,
                    FirstExpr      = new WColumnReferenceExpression(EDGE_SELECT_TAG, KW_EDGE_ID),
                    SecondExpr     = new WValueExpression(edgeId, true)
                }, BooleanBinaryExpressionType.And);

                string partition = command.Connection.GetDocumentPartition(vertexObject);
                if (partition != null)
                {
                    jsonQuery.FlatProperties.Add(partition);
                    jsonQuery.WhereConjunction(new WBooleanComparisonExpression
                    {
                        ComparisonType = BooleanComparisonType.Equals,
                        // TODO: new type to represent this??
                        FirstExpr  = new WValueExpression($"{VERTEX_ALIAS}{command.Connection.GetPartitionPathIndexer()}", false),
                        SecondExpr = new WValueExpression(partition, true)
                    }, BooleanBinaryExpressionType.And);
                }


                JObject result = command.Connection.CreateDatabasePortal().GetEdgeDocument(jsonQuery);
                edgeDocId  = (string)result?[VERTEX_ALIAS]?[KW_DOC_ID];
                edgeObject = (JObject)result?[EDGE_SELECT_TAG];
            }
        }