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]; } }