/// <summary> /// Add an edge from one vertex (source) to another (sink) /// NOTE: Both the source and sink vertex are modified. /// NOTE: This function may upload the edge-document. /// NOTE: srcVertex and sinkVertex are updated and uploaded. /// </summary> /// <param name="connection"></param> /// <param name="srcId"></param> /// <param name="sinkId"></param> /// <param name="srcVertexField"></param> /// <param name="sinkVertexField"></param> /// <param name="edgeJsonObject"></param> /// <param name="srcVertexObject"></param> /// <param name="sinkVertexObject"></param> /// <param name="outEdgeObject"></param> /// <param name="outEdgeDocID"></param> /// <param name="inEdgeObject"></param> /// <param name="inEdgeDocID"></param> public static void InsertEdgeAndUpload( GraphViewConnection connection, string srcId, string sinkId, VertexField srcVertexField, VertexField sinkVertexField, JObject edgeJsonObject, JObject srcVertexObject, JObject sinkVertexObject, out JObject outEdgeObject, out string outEdgeDocID, out JObject inEdgeObject, out string inEdgeDocID) { long edgeOffset = (long)srcVertexObject["_nextEdgeOffset"]; srcVertexObject["_nextEdgeOffset"] = edgeOffset + 1; outEdgeObject = (JObject)edgeJsonObject.DeepClone(); inEdgeObject = (JObject)edgeJsonObject.DeepClone(); // Add "id" property to edgeObject if desired if (connection.GenerateEdgeId) { string guid = GraphViewConnection.GenerateDocumentId(); outEdgeObject["_edgeId"] = guid; inEdgeObject["_edgeId"] = guid; } string srcLabel = srcVertexObject["label"]?.ToString(); string sinkLabel = sinkVertexObject["label"]?.ToString(); GraphViewJsonCommand.UpdateEdgeMetaProperty(outEdgeObject, edgeOffset, false, sinkId, sinkLabel); GraphViewJsonCommand.UpdateEdgeMetaProperty(inEdgeObject, edgeOffset, true, srcId, srcLabel); InsertEdgeObjectInternal(connection, srcVertexObject, srcVertexField, outEdgeObject, false, out outEdgeDocID); // srcVertex uploaded InsertEdgeObjectInternal(connection, sinkVertexObject, sinkVertexField, inEdgeObject, true, out inEdgeDocID); // sinkVertex uploaded }
internal override List <RawRecord> CrossApply(RawRecord record) { List <RawRecord> results = new List <RawRecord>(); FieldObject target = record[this._targetIndex]; if (target != null) { VertexField vertex = target as VertexField; if (vertex != null) { RawRecord r = new RawRecord(); r.Append(new StringField(vertex.VertexMetaProperties[KW_DOC_ID].ToValue)); results.Add(r); } VertexSinglePropertyField vertexSingleProperty = target as VertexSinglePropertyField; if (vertexSingleProperty != null) { RawRecord r = new RawRecord(); r.Append(new StringField(vertexSingleProperty.PropertyId)); results.Add(r); } EdgeField edge = target as EdgeField; if (edge != null) { RawRecord r = new RawRecord(); r.Append(new StringField(edge.EdgeId)); results.Add(r); } } return(results); }
internal override RawRecord DataModify(RawRecord record) { JObject vertexObject = this._vertexDocument; string vertexId = GraphViewConnection.GenerateDocumentId(); Debug.Assert(vertexObject["id"] == null); Debug.Assert(vertexObject["_partition"] == null); vertexObject["id"] = vertexId; vertexObject["_partition"] = vertexId; this.Connection.CreateDocumentAsync(vertexObject).Wait(); VertexField vertexField = Connection.VertexCache.GetVertexField(vertexId, vertexObject); RawRecord result = new RawRecord(); foreach (string fieldName in _projectedFieldList) { FieldObject fieldValue = vertexField[fieldName]; result.Append(fieldValue); } return(result); }
public static void Run() { // Initialize scene object Scene scene = new Scene(); // Initialize Node class object Node cubeNode = new Node("box"); //ExStart:ConvertBoxMeshtoTriangleMeshCustomMemoryLayout // get mesh of the Box Mesh box = (new Box()).ToMesh(); //create a customized vertex layout VertexDeclaration vd = new VertexDeclaration(); VertexField position = vd.AddField(VertexFieldDataType.FVector4, VertexFieldSemantic.Position); vd.AddField(VertexFieldDataType.FVector3, VertexFieldSemantic.Normal); // get a triangle mesh TriMesh triMesh = TriMesh.FromMesh(box); //ExEnd:ConvertBoxMeshtoTriangleMeshCustomMemoryLayout // Point node to the Mesh geometry cubeNode.Entity = box; // Add Node to a scene scene.RootNode.ChildNodes.Add(cubeNode); // The path to the documents directory. string MyDir = RunExamples.GetDataDir() + RunExamples.GetOutputFilePath("BoxToTriangleMeshCustomMemoryLayoutScene.fbx"); // Save 3D scene in the supported file formats scene.Save(MyDir, FileFormat.FBX7400ASCII); Console.WriteLine("\n Converted a Box mesh to triangle mesh with custom memory layout of the vertex successfully.\nFile saved at " + MyDir); }
private void DropVertexSingleProperty(VertexSinglePropertyField vp) { // Update DocDB VertexField vertexField = vp.VertexProperty.Vertex; JObject vertexObject = this.connection.RetrieveDocumentById(vertexField.VertexId); Debug.Assert(vertexObject[vp.PropertyName] != null); JArray vertexProperty = (JArray)vertexObject[vp.PropertyName]; vertexProperty .First(singleProperty => (string)singleProperty["_propId"] == vp.PropertyId) .Remove(); if (vertexObject.Count == 0) { vertexProperty.Remove(); } this.connection.ReplaceOrDeleteDocumentAsync(vertexField.VertexId, vertexObject, (string)vertexObject["_partition"]).Wait(); // Update vertex field VertexPropertyField vertexPropertyField = vertexField.VertexProperties[vp.PropertyName]; bool found = vertexPropertyField.Multiples.Remove(vp.PropertyId); Debug.Assert(found); if (!vertexPropertyField.Multiples.Any()) { vertexField.VertexProperties.Remove(vp.PropertyName); } }
public DeltaEdgeField(EdgeField outEdgeField, VertexField srcVertexField, EdgeField inEdgeField, VertexField sinkVertexField, bool useReverseEdges) { this.outEdgeField = outEdgeField; this.inEdgeField = inEdgeField; this.srcVertexField = srcVertexField; this.sinkVertexField = sinkVertexField; this.UseReverseEdges = useReverseEdges; this.deltaProperties = new Dictionary <string, Tuple <EdgeDeltaType, JValue> >(); }
private void UpdatePropertiesOfVertex(VertexField vertex) { JObject vertexDocument = this.Connection.RetrieveDocumentById(vertex.VertexId); foreach (WPropertyExpression property in this.updateProperties) { Debug.Assert(property.Value != null); VertexPropertyField vertexProperty; string name = property.Key.Value; // Construct single property JObject meta = new JObject(); foreach (KeyValuePair <WValueExpression, WValueExpression> pair in property.MetaProperties) { meta[pair.Key.Value] = pair.Value.ToJValue(); } JObject singleProperty = new JObject { ["_value"] = property.Value.ToJValue(), ["_propId"] = GraphViewConnection.GenerateDocumentId(), ["_meta"] = meta, }; // Set / Append to multiProperty JArray multiProperty; if (vertexDocument[name] == null) { multiProperty = new JArray(); vertexDocument[name] = multiProperty; } else { multiProperty = (JArray)vertexDocument[name]; } if (property.Cardinality == GremlinKeyword.PropertyCardinality.single) { multiProperty.Clear(); } multiProperty.Add(singleProperty); // Update vertex field bool existed = vertex.VertexProperties.TryGetValue(name, out vertexProperty); if (!existed) { vertexProperty = new VertexPropertyField(vertexDocument.Property(name), vertex); vertex.VertexProperties.Add(name, vertexProperty); } else { vertexProperty.Replace(vertexDocument.Property(name)); } } // Upload to DocDB this.Connection.ReplaceOrDeleteDocumentAsync(vertex.VertexId, vertexDocument, (string)vertexDocument["_partition"]).Wait(); }
public List <VertexField> GetVerticesByIds(HashSet <string> vertexId, GraphViewCommand command, string partition, bool constructEdges = false) { const string NODE_ALIAS = "node"; var jsonQuery = new JsonQuery { NodeAlias = NODE_ALIAS, RawWhereClause = new WBooleanComparisonExpression { ComparisonType = BooleanComparisonType.Equals, FirstExpr = new WColumnReferenceExpression(NODE_ALIAS, DocumentDBKeywords.KW_EDGEDOC_IDENTIFIER), SecondExpr = new WValueExpression("null") } }; // SELECT node jsonQuery.AddSelectElement(NODE_ALIAS); jsonQuery.FlatProperties.Add(DocumentDBKeywords.KW_EDGEDOC_IDENTIFIER); jsonQuery.WhereConjunction(new WInPredicate( new WColumnReferenceExpression(NODE_ALIAS, GremlinKeyword.NodeID), vertexId.ToList()), BooleanBinaryExpressionType.And); if (partition != null) { jsonQuery.WhereConjunction(new WBooleanComparisonExpression { ComparisonType = BooleanComparisonType.Equals, FirstExpr = new WValueExpression($"{NODE_ALIAS}{command.Connection.GetPartitionPathIndexer()}", false), SecondExpr = new WValueExpression(partition, true) }, BooleanBinaryExpressionType.And); } jsonQuery.NodeProperties = new List <string> { "node", "*" }; jsonQuery.EdgeProperties = new List <string>(); IEnumerator <Tuple <VertexField, RawRecord> > queryResult = this.GetVerticesAndEdgesViaVertices(jsonQuery, command); List <VertexField> result = new List <VertexField>(); while (queryResult.MoveNext()) { VertexField vertex = queryResult.Current.Item1; result.Add(vertex); } if (constructEdges) { // TODO: need double check on JsonServer EdgeDocumentHelper.ConstructLazyAdjacencyList(command, EdgeType.Both, vertexId, new HashSet <string>()); } return(result); }
private void DropVertex(VertexField vertexField) { RawRecord record = new RawRecord(); record.Append(new StringField(vertexField.VertexId)); // nodeIdIndex DropNodeOperator op = new DropNodeOperator(this.dummyInputOp, this.connection, 0); op.DataModify(record); // Now VertexCacheObject has been updated (in DataModify) }
public VertexField GetVertexField(string vertexId) { VertexField result; if (!this._cachedVertexField.TryGetValue(vertexId, out result)) { JObject vertexObject = this.Connection.RetrieveDocumentById(vertexId); result = new VertexField(this.Connection, vertexObject); this._cachedVertexField.Add(vertexId, result); } return(result); }
private void UpdateNodeProperties( Dictionary <string, JObject> documentsMap, string vertexId, JObject vertexDocObject, List <Tuple <WValueExpression, WValueExpression, int> > propList, UpdatePropertyMode mode) { VertexField vertexField = this.Connection.VertexCache.GetVertexField(vertexId); // Drop all non-reserved properties if (propList.Count == 1 && !propList[0].Item1.SingleQuoted && propList[0].Item1.Value.Equals("*", StringComparison.OrdinalIgnoreCase) && !propList[0].Item2.SingleQuoted && propList[0].Item2.Value.Equals("null", StringComparison.OrdinalIgnoreCase)) { List <string> toBeDroppedPropertiesNames = GraphViewJsonCommand.DropAllNodeProperties(vertexDocObject); foreach (var propertyName in toBeDroppedPropertiesNames) { vertexField.VertexProperties.Remove(propertyName); } } else { foreach (var t in propList) { WValueExpression keyExpression = t.Item1; WValueExpression valueExpression = t.Item2; if (mode == UpdatePropertyMode.Set) { JProperty updatedProperty = GraphViewJsonCommand.UpdateProperty(vertexDocObject, keyExpression, valueExpression); if (updatedProperty == null) { vertexField.VertexProperties.Remove(keyExpression.Value); } else { vertexField.UpdateVertexProperty(updatedProperty.Name, updatedProperty.Value.ToString(), JsonDataTypeHelper.GetJsonDataType(updatedProperty.Value.Type)); } } else { throw new NotImplementedException(); } } } documentsMap[vertexId] = vertexDocObject; }
// TODO: Batch upload for the DropEdge part internal override RawRecord DataModify(RawRecord record) { string vertexId = record[this._nodeIdIndex].ToValue; // Temporarily change DropEdgeOperator dropEdgeOp = new DropEdgeOperator(null, this.Connection, 0, 1); RawRecord temp = new RawRecord(2); VertexField vertex = this.Connection.VertexCache.GetVertexField(vertexId); // Save a copy of Edges _IDs & drop outgoing edges List <long> outEdgeOffsets = vertex.AdjacencyList.AllEdges.Select(e => e.Offset).ToList(); foreach (long outEdgeOffset in outEdgeOffsets) { temp.fieldValues[0] = new StringField(vertexId); temp.fieldValues[1] = new StringField(outEdgeOffset.ToString()); dropEdgeOp.DataModify(temp); } AdjacencyListField revAdjacencyListField = Connection.UseReverseEdges ? vertex.RevAdjacencyList : EdgeDocumentHelper.GetReverseAdjacencyListOfVertex(Connection, vertexId); // Save a copy of incoming Edges <srcVertexId, edgeOffsetInSrcVertex> & drop them List <Tuple <string, long> > inEdges = revAdjacencyListField.AllEdges.Select( e => new Tuple <string, long>(e.OutV, e.Offset)).ToList(); foreach (var inEdge in inEdges) { temp.fieldValues[0] = new StringField(inEdge.Item1); // srcVertexId temp.fieldValues[1] = new StringField(inEdge.Item2.ToString()); // edgeOffsetInSrcVertex dropEdgeOp.DataModify(temp); } // Delete the node-document! #if DEBUG JObject vertexObject = this.Connection.RetrieveDocumentById(vertexId); Debug.Assert(vertexObject != null); Debug.Assert(vertexObject["_edge"] is JArray); Debug.Assert(((JArray)vertexObject["_edge"]).Count == 0); Debug.Assert(vertexObject["_reverse_edge"] is JArray); Debug.Assert(((JArray)vertexObject["_reverse_edge"]).Count == 0); #endif // NOTE: for vertex document, id = _partition this.Connection.ReplaceOrDeleteDocumentAsync(vertexId, null, vertexId).Wait(); // Update VertexCache this.Connection.VertexCache.TryRemoveVertexField(vertexId); return(null); }
internal override RawRecord DataModify(RawRecord record) { string srcId = record[this._srcIdIndex].ToValue; long edgeOffset = long.Parse(record[this._edgeOffsetIndex].ToValue); JObject srcEdgeObject; string srcEdgeDocId, sinkEdgeDocId; JObject srcVertexObject = this.Connection.RetrieveDocumentById(srcId); EdgeDocumentHelper.FindEdgeBySourceAndOffset( this.Connection, srcVertexObject, srcId, edgeOffset, false, out srcEdgeObject, out srcEdgeDocId); if (srcEdgeObject == null) { //TODO: Check is this condition alright? return(null); } string sinkId = (string)srcEdgeObject["_sinkV"]; JObject sinkVertexObject; if (!string.Equals(sinkId, srcId)) { sinkVertexObject = this.Connection.RetrieveDocumentById(sinkId); JObject sinkEdgeObject; EdgeDocumentHelper.FindEdgeBySourceAndOffset( this.Connection, sinkVertexObject, srcId, edgeOffset, true, out sinkEdgeObject, out sinkEdgeDocId); } else { sinkVertexObject = srcVertexObject; // NOTE: Must not use DeepClone() here! sinkEdgeDocId = srcEdgeDocId; } Dictionary <string, Tuple <JObject, string> > uploadDocuments = new Dictionary <string, Tuple <JObject, string> >(); EdgeDocumentHelper.RemoveEdge(uploadDocuments, this.Connection, srcEdgeDocId, srcVertexObject, false, srcId, edgeOffset); EdgeDocumentHelper.RemoveEdge(uploadDocuments, this.Connection, sinkEdgeDocId, sinkVertexObject, true, srcId, edgeOffset); this.Connection.ReplaceOrDeleteDocumentsAsync(uploadDocuments).Wait(); VertexField srcVertexField = this.Connection.VertexCache.GetVertexField(srcId, srcVertexObject); VertexField sinkVertexField = this.Connection.VertexCache.GetVertexField(sinkId, sinkVertexObject); srcVertexField.AdjacencyList.RemoveEdgeField(srcId, edgeOffset); sinkVertexField.RevAdjacencyList.RemoveEdgeField(srcId, edgeOffset); return(null); }
internal override RawRecord DataModify(RawRecord record) { FieldObject dropTarget = record[this.dropTargetIndex]; VertexField vertexField = dropTarget as VertexField;; if (vertexField != null) { this.DropVertex(vertexField); return(null); } EdgeField edgeField = dropTarget as EdgeField; if (edgeField != null) { this.DropEdge(edgeField); return(null); } PropertyField property = dropTarget as PropertyField; if (property != null) { if (property is VertexPropertyField) { this.DropVertexProperty((VertexPropertyField)property); } else if (property is VertexSinglePropertyField) { this.DropVertexSingleProperty((VertexSinglePropertyField)property); } else if (property is EdgePropertyField) { this.DropEdgeProperty((EdgePropertyField)property); } else { this.DropVertexPropertyMetaProperty((ValuePropertyField)property); } return(null); } // // Should not reach here // throw new Exception("BUG: Should not get here"); return(null); }
private void DropVertexProperty(VertexPropertyField vp) { // Update DocDB VertexField vertexField = vp.Vertex; JObject vertexObject = this.connection.RetrieveDocumentById(vertexField.VertexId); Debug.Assert(vertexObject[vp.PropertyName] != null); vertexObject[vp.PropertyName].Remove(); this.connection.ReplaceOrDeleteDocumentAsync(vertexField.VertexId, vertexObject, (string)vertexObject["_partition"]).Wait(); // Update vertex field vertexField.VertexProperties.Remove(vp.PropertyName); }
public JObject ConstructNodeJsonDocument(out List <string> projectedFieldList) { JObject nodeJsonDocument = new JObject(); projectedFieldList = new List <string>(GraphViewReservedProperties.ReservedNodeProperties); for (var i = 0; i < Parameters.Count; i += 2) { var key = (Parameters[i] as WValueExpression).Value; //GraphViewJsonCommand.UpdateProperty(nodeJsonDocument, Parameters[i] as WValueExpression, // Parameters[i + 1] as WValueExpression); GraphViewJsonCommand.UpdateProperty(nodeJsonDocument, Parameters[i] as WValueExpression, Parameters[i + 1] as WValueExpression); string name = (Parameters[i] as WValueExpression).Value; JToken value = (Parameters[i + 1] as WValueExpression).ToJValue(); if (value != null) { if (VertexField.IsVertexMetaProperty(name)) { nodeJsonDocument[name] = value; } else { nodeJsonDocument[name] = new JArray { new JObject { ["_value"] = value, ["_propId"] = GraphViewConnection.GenerateDocumentId(), ["_meta"] = new JObject(), }, }; } } if (!projectedFieldList.Contains(key)) { projectedFieldList.Add(key); } } //nodeJsonDocument = GraphViewJsonCommand.insert_property(nodeJsonDocument, "[]", "_edge").ToString(); //nodeJsonDocument = GraphViewJsonCommand.insert_property(nodeJsonDocument, "[]", "_reverse_edge").ToString(); nodeJsonDocument["_edge"] = new JArray(); nodeJsonDocument["_reverse_edge"] = new JArray(); nodeJsonDocument["_nextEdgeOffset"] = 0; return(nodeJsonDocument); }
internal void AddOrUpdateVertexDelta(VertexField vertexField, DeltaLog log) { string vertexId = vertexField.VertexId; DeltaVertexField delta; if (vertexDelta.ContainsKey(vertexId)) { delta = vertexDelta[vertexId]; } else { delta = new DeltaVertexField(vertexField); vertexDelta.Add(vertexId, delta); } delta.AddDeltaLog(log); }
internal void AddOrUpdateEdgeDelta(EdgeField outEdgeField, VertexField srcVertexField, EdgeField inEdgeField, VertexField sinkVertexField, DeltaLog log, bool useReverseEdges) { string edgeId = outEdgeField.EdgeId; DeltaEdgeField delta; if (edgeDelta.ContainsKey(edgeId)) { delta = edgeDelta[edgeId]; } else { delta = new DeltaEdgeField(outEdgeField, srcVertexField, inEdgeField, sinkVertexField, useReverseEdges); edgeDelta[edgeId] = delta; } delta.AddDeltaLog(log); }
internal override RawRecord DataModify(RawRecord record) { FieldObject updateTarget = record[this.updateTargetIndex]; VertexField vertex = updateTarget as VertexField;; if (vertex != null) { this.UpdatePropertiesOfVertex(vertex); return(record); } EdgeField edge = updateTarget as EdgeField; if (edge != null) { this.UpdatePropertiesOfEdge(edge); return(record); } PropertyField property = updateTarget as PropertyField; if (property != null) { if (property is VertexSinglePropertyField) { this.UpdateMetaPropertiesOfSingleVertexProperty((VertexSinglePropertyField)property); } else { throw new GraphViewException($"BUG: updateTarget is {nameof(PropertyField)}: {property.GetType()}"); } return(record); } // // Should not reach here // throw new Exception("BUG: Should not get here!"); }
public VertexField AddOrUpdateVertexField(string vertexId, JObject vertexObject) { VertexField vertexField; if (this._cachedVertexField.TryGetValue(vertexId, out vertexField)) { // TODO: Update? } else { // // Update saved etags when Constructing a vertex field // NOTE: For each vertex document, only ONE VertexField will be constructed ever. // this.SaveCurrentEtagNoOverride(vertexObject); vertexField = new VertexField(this.Connection, vertexObject); this._cachedVertexField.Add(vertexId, vertexField); } return(vertexField); }
private void DropVertexPropertyMetaProperty(ValuePropertyField metaProperty) { Debug.Assert(metaProperty.Parent is VertexSinglePropertyField); VertexSinglePropertyField vertexSingleProperty = (VertexSinglePropertyField)metaProperty.Parent; VertexField vertexField = vertexSingleProperty.VertexProperty.Vertex; JObject vertexObject = this.connection.RetrieveDocumentById(vertexField.VertexId); Debug.Assert(vertexObject[vertexSingleProperty.PropertyName] != null); JToken propertyJToken = ((JArray)vertexObject[vertexSingleProperty.PropertyName]) .First(singleProperty => (string)singleProperty["_propId"] == vertexSingleProperty.PropertyId); JObject metaPropertyJObject = (JObject)propertyJToken?["_meta"]; metaPropertyJObject?.Property(metaProperty.PropertyName)?.Remove(); // Update DocDB this.connection.ReplaceOrDeleteDocumentAsync(vertexField.VertexId, vertexObject, (string)vertexObject["_partition"]).Wait(); // Update vertex field vertexSingleProperty.MetaProperties.Remove(metaProperty.PropertyName); }
public override FieldObject Evaluate(RawRecord record) { FieldObject checkObject = record[_checkFieldIndex]; VertexField vertexField = checkObject as VertexField; EdgeField edgeField = checkObject as EdgeField; if (vertexField != null) { if (vertexField.AllProperties.Count(pf => pf.PropertyName == _propertyName) > 0) { return(new StringField("true", JsonDataType.Boolean)); } else { return(new StringField("false", JsonDataType.Boolean)); } } else if (edgeField != null) { if (edgeField.EdgeProperties.ContainsKey(_propertyName)) { return(new StringField("true", JsonDataType.Boolean)); } else { return(new StringField("false", JsonDataType.Boolean)); } } else { throw new GraphViewException( "HasProperty() function can only be applied to a VertexField or EdgeField but now the object is " + checkObject.GetType()); } }
/// <summary> /// Add an edge from one vertex (source) to another (sink) /// NOTE: Both the source and sink vertex are modified. /// NOTE: This function may upload the edge-document. /// NOTE: srcVertex and sinkVertex are updated and uploaded. /// </summary> /// <param name="connection"></param> /// <param name="srcId"></param> /// <param name="sinkId"></param> /// <param name="srcVertexField"></param> /// <param name="sinkVertexField"></param> /// <param name="edgeJsonObject"></param> /// <param name="srcVertexObject"></param> /// <param name="sinkVertexObject"></param> /// <param name="outEdgeObject"></param> /// <param name="outEdgeDocID"></param> /// <param name="inEdgeObject"></param> /// <param name="inEdgeDocID"></param> public static void InsertEdgeAndUpload( GraphViewConnection connection, string srcId, string sinkId, VertexField srcVertexField, VertexField sinkVertexField, JObject edgeJsonObject, JObject srcVertexObject, JObject sinkVertexObject, out JObject outEdgeObject, out string outEdgeDocID, out JObject inEdgeObject, out string inEdgeDocID) { //long edgeOffset = (long)srcVertexObject[KW_VERTEX_NEXTOFFSET]; //srcVertexObject[KW_VERTEX_NEXTOFFSET] = edgeOffset + 1; outEdgeObject = (JObject)edgeJsonObject.DeepClone(); inEdgeObject = (JObject)edgeJsonObject.DeepClone(); // Add "id" property to edgeObject string edgeId = GraphViewConnection.GenerateDocumentId(); string srcLabel = srcVertexObject[KW_VERTEX_LABEL]?.ToString(); string sinkLabel = sinkVertexObject[KW_VERTEX_LABEL]?.ToString(); GraphViewJsonCommand.UpdateEdgeMetaProperty(outEdgeObject, edgeId, false, sinkId, sinkLabel); GraphViewJsonCommand.UpdateEdgeMetaProperty(inEdgeObject, edgeId, true, srcId, srcLabel); InsertEdgeObjectInternal(connection, srcVertexObject, srcVertexField, outEdgeObject, false, out outEdgeDocID); // srcVertex uploaded if (connection.UseReverseEdges) { InsertEdgeObjectInternal(connection, sinkVertexObject, sinkVertexField, inEdgeObject, true, out inEdgeDocID); // sinkVertex uploaded } else { inEdgeDocID = EdgeDocumentHelper.VirtualReverseEdgeDocId; } }
/// <summary> /// Insert edgeObject to one a vertex. /// NOTE: vertex-document and edge-document(s) are uploaded. /// NOTE: If changing _edge/_reverse_edge field from JArray to JObject, the "EdgeDocId" of existing /// edges in VertexCache are updated (from null to the newly created edge-document's id) /// NOTE: Adding the newly created edge into VertexCache is not operated by this function. Actually, /// if called by <see cref="UpdateEdgeProperty"/>, VertexCache should be updated by setting an /// edge's property, but not adding a new edge. /// </summary> /// <param name="connection"></param> /// <param name="vertexObject"></param> /// <param name="vertexField">Can be null if we already know edgeContainer is JObject</param> /// <param name="edgeObject"></param> /// <param name="isReverse"></param> /// <param name="newEdgeDocId"></param> private static void InsertEdgeObjectInternal( GraphViewConnection connection, JObject vertexObject, VertexField vertexField, JObject edgeObject, bool isReverse, out string newEdgeDocId) { bool tooLarge; JToken edgeContainer = vertexObject[isReverse ? "_reverse_edge" : "_edge"]; // JArray or JObject if (edgeContainer is JObject) { // Now it is a large-degree vertex, and contains at least 1 edge-document JArray edgeDocumentsArray = (JArray)edgeContainer["_edges"]; Debug.Assert(edgeDocumentsArray != null, "edgeDocuments != null"); Debug.Assert(edgeDocumentsArray.Count > 0, "edgeDocuments.Count > 0"); string lastEdgeDocId = (string)edgeDocumentsArray.Last["id"]; JObject edgeDocument = connection.RetrieveDocumentById(lastEdgeDocId); Debug.Assert(((string)edgeDocument["id"]).Equals(lastEdgeDocId), "((string)edgeDocument['id']).Equals(lastEdgeDocId)"); Debug.Assert((bool)edgeDocument["_is_reverse"] == isReverse, "(bool)edgeDocument['_is_reverse'] == isReverse"); Debug.Assert((string)edgeDocument["_vertex_id"] == (string)vertexObject["id"], "(string)edgeDocument['_vertex_id'] == (string)vertexObject['id']"); JArray edgesArray = (JArray)edgeDocument["_edge"]; Debug.Assert(edgesArray != null, "edgesArray != null"); Debug.Assert(edgesArray.Count > 0, "edgesArray.Count > 0"); if (connection.EdgeSpillThreshold == 0) { // Don't spill an edge-document until it is too large edgesArray.Add(edgeObject); tooLarge = false; } else { // Explicitly specified a threshold Debug.Assert(connection.EdgeSpillThreshold > 0, "connection.EdgeSpillThreshold > 0"); if (edgesArray.Count >= connection.EdgeSpillThreshold) { // The threshold is reached! tooLarge = true; } else { // The threshold is not reached edgesArray.Add(edgeObject); tooLarge = false; } } // If the edge-document is not too large (reach the threshold), try to // upload the edge into the document if (!tooLarge) { UploadOne(connection, lastEdgeDocId, edgeDocument, out tooLarge); } if (tooLarge) { // The edge is too large to be filled into the last edge-document // or the threashold is reached: // Create a new edge-document to store the edge. JObject edgeDocObject = new JObject { ["id"] = GraphViewConnection.GenerateDocumentId(), ["_partition"] = vertexObject["_partition"], ["_is_reverse"] = isReverse, ["_vertex_id"] = (string)vertexObject["id"], ["_edge"] = new JArray(edgeObject) }; lastEdgeDocId = connection.CreateDocumentAsync(edgeDocObject).Result; // Add the newly create edge-document to vertexObject & upload the vertexObject edgeDocumentsArray.Add(new JObject { ["id"] = lastEdgeDocId }); } newEdgeDocId = lastEdgeDocId; // Upload the vertex documention (at least, its _nextXxx is changed) bool dummyTooLarge; UploadOne(connection, (string)vertexObject["id"], vertexObject, out dummyTooLarge); Debug.Assert(!dummyTooLarge); } else if (edgeContainer is JArray) { ((JArray)edgeContainer).Add(edgeObject); if (connection.EdgeSpillThreshold == 0) { // Don't spill an edge-document until it is too large tooLarge = false; } else { // Explicitly specified a threshold Debug.Assert(connection.EdgeSpillThreshold > 0, "connection.EdgeSpillThreshold > 0"); tooLarge = (((JArray)edgeContainer).Count >= connection.EdgeSpillThreshold); } if (!tooLarge) { UploadOne(connection, (string)vertexObject["id"], vertexObject, out tooLarge); } if (tooLarge) { string existEdgeDocId; SpillVertexEdgesToDocument(connection, vertexObject, out existEdgeDocId, out newEdgeDocId); // Update the in & out edges in vertex field if (isReverse) { Debug.Assert(vertexField.RevAdjacencyList.AllEdges.All(edge => edge.EdgeDocID == null)); foreach (EdgeField edge in vertexField.RevAdjacencyList.AllEdges) { edge.EdgeDocID = existEdgeDocId; } } else { Debug.Assert(vertexField.AdjacencyList.AllEdges.All(edge => edge.EdgeDocID == null)); foreach (EdgeField edge in vertexField.AdjacencyList.AllEdges) { edge.EdgeDocID = existEdgeDocId; } } } else { newEdgeDocId = null; } } else { throw new Exception($"BUG: edgeContainer should either be JObject or JArray, but now: {edgeContainer?.GetType()}"); } }
public IEnumerator <Tuple <VertexField, RawRecord> > GetVerticesAndEdgesViaVertices(JsonQuery vertexQuery, GraphViewCommand command) { IEnumerable <JObject> items = this.ExecuteQueryScript(vertexQuery); List <string> nodeProperties = new List <string>(vertexQuery.NodeProperties); List <string> edgeProperties = new List <string>(vertexQuery.EdgeProperties); string nodeAlias = nodeProperties[0]; // Skip i = 0, which is the (node.* as nodeAlias) field nodeProperties.RemoveAt(0); // // TODO: Refactor // string edgeAlias = null; bool isReverseAdj = false; bool isStartVertexTheOriginVertex = false; bool crossApplyEdgeOnServer = edgeProperties.Any(); if (crossApplyEdgeOnServer) { edgeAlias = edgeProperties[0]; isReverseAdj = bool.Parse(edgeProperties[1]); isStartVertexTheOriginVertex = bool.Parse(edgeProperties[2]); edgeProperties.RemoveAt(0); edgeProperties.RemoveAt(0); edgeProperties.RemoveAt(0); } // // Batch strategy: // - For "small" vertexes, they have been cross applied on the server side // - For "large" vertexes, just return the VertexField, the adjacency list decoder will // construct spilled adjacency lists in batch mode and cross apply edges after that // Func <VertexField, string, Tuple <VertexField, RawRecord> > makeCrossAppliedRecord = (vertexField, edgeId) => { Debug.Assert(vertexField != null); RawRecord nodeRecord = new RawRecord(); // // Fill node property field // foreach (string propertyName in nodeProperties) { FieldObject propertyValue = vertexField[propertyName]; nodeRecord.Append(propertyValue); } RawRecord edgeRecord = new RawRecord(edgeProperties.Count); EdgeField edgeField = ((AdjacencyListField)vertexField[isReverseAdj ? DocumentDBKeywords.KW_VERTEX_REV_EDGE : DocumentDBKeywords.KW_VERTEX_EDGE]) .GetEdgeField(edgeId, true); string startVertexId = vertexField.VertexId; AdjacencyListDecoder.FillMetaField(edgeRecord, edgeField, startVertexId, vertexField.Partition, isStartVertexTheOriginVertex, isReverseAdj); AdjacencyListDecoder.FillPropertyField(edgeRecord, edgeField, edgeProperties); nodeRecord.Append(edgeRecord); return(new Tuple <VertexField, RawRecord>(vertexField, nodeRecord)); }; Func <VertexField, Tuple <VertexField, RawRecord> > makeRawRecord = (vertexField) => { Debug.Assert(vertexField != null); RawRecord rawRecord = new RawRecord(); // // Fill node property field // foreach (string propertyName in nodeProperties) { FieldObject propertyValue = vertexField[propertyName]; rawRecord.Append(propertyValue); } return(new Tuple <VertexField, RawRecord>(vertexField, rawRecord)); }; HashSet <string> uniqueVertexIds = new HashSet <string>(); HashSet <string> uniqueEdgeIds = new HashSet <string>(); foreach (JObject dynamicItem in items) { JObject tmpVertexObject = (JObject)((JObject)dynamicItem)[nodeAlias]; string vertexId = (string)tmpVertexObject[DocumentDBKeywords.KW_DOC_ID]; if (crossApplyEdgeOnServer) { // Note: since vertex properties can be multi-valued, // a DocumentDB query needs a join clause in the FROM clause // to retrieve vertex property values, which may result in // the same vertex being returned multiple times. // We use the hash set uniqueVertexIds to ensure one vertex is // produced only once. if (EdgeDocumentHelper.IsBuildingTheAdjacencyListLazily( tmpVertexObject, isReverseAdj, this.Connection.UseReverseEdges) && uniqueVertexIds.Add(vertexId)) { VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeRawRecord(vertexField)); } else // When the DocumentDB query crosses apply edges { JObject edgeObjct = (JObject)((JObject)dynamicItem)[edgeAlias]; string edgeId = (string)edgeObjct[DocumentDBKeywords.KW_EDGE_ID]; if (uniqueEdgeIds.Add(edgeId)) { VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeCrossAppliedRecord(vertexField, edgeId)); } } } else { if (!uniqueVertexIds.Add(vertexId)) { continue; } VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, tmpVertexObject); yield return(makeRawRecord(vertexField)); } } }
public IEnumerator <RawRecord> GetVerticesAndEdgesViaEdges(JsonQuery edgeQuery, GraphViewCommand command) { IEnumerable <JObject> items = this.ExecuteQueryScript(edgeQuery); List <string> nodeProperties = new List <string>(edgeQuery.NodeProperties); List <string> edgeProperties = new List <string>(edgeQuery.EdgeProperties); string nodeAlias = nodeProperties[0]; nodeProperties.RemoveAt(0); string edgeAlias = edgeProperties[0]; edgeProperties.RemoveAt(0); HashSet <string> spilledVertexIdSet = new HashSet <string>(); HashSet <string> spilledVertexPartitionSet = new HashSet <string>(); // // <vertex id, edge id> // Dictionary <string, List <string> > vertexIdAndEdgeIdsDict = new Dictionary <string, List <string> >(); // // <vertex id, <edgeDocumentId, edgeObject>> // Dictionary <string, List <Tuple <string, JObject> > > vertexIdAndEdgeObjectsDict = new Dictionary <string, List <Tuple <string, JObject> > >(); foreach (JObject dynamicItem in items) { JObject tmpObject = (JObject)dynamicItem[nodeAlias]; JObject edgeObject = (JObject)dynamicItem[edgeAlias]; // // This is a spilled edge document // if (tmpObject[DocumentDBKeywords.KW_EDGEDOC_VERTEXID] != null) { string vertexId = tmpObject[DocumentDBKeywords.KW_EDGEDOC_VERTEXID].ToString(); spilledVertexIdSet.Add(vertexId); string partition = this.Connection.GetDocumentPartition(tmpObject); if (partition != null) { spilledVertexPartitionSet.Add(partition); } List <Tuple <string, JObject> > edgeObjects; if (!vertexIdAndEdgeObjectsDict.TryGetValue(vertexId, out edgeObjects)) { edgeObjects = new List <Tuple <string, JObject> >(); vertexIdAndEdgeObjectsDict.Add(vertexId, edgeObjects); } edgeObjects.Add(new Tuple <string, JObject>((string)tmpObject[DocumentDBKeywords.KW_DOC_ID], edgeObject)); List <string> edgeIds; if (!vertexIdAndEdgeIdsDict.TryGetValue(vertexId, out edgeIds)) { edgeIds = new List <string>(); vertexIdAndEdgeIdsDict.Add(vertexId, edgeIds); } edgeIds.Add((string)edgeObject[DocumentDBKeywords.KW_DOC_ID]); } else { string vertexId = (string)tmpObject[DocumentDBKeywords.KW_DOC_ID]; command.VertexCache.AddOrUpdateVertexField(vertexId, tmpObject); List <string> edgeIds; if (!vertexIdAndEdgeIdsDict.TryGetValue(vertexId, out edgeIds)) { edgeIds = new List <string>(); vertexIdAndEdgeIdsDict.Add(vertexId, edgeIds); } edgeIds.Add((string)edgeObject[DocumentDBKeywords.KW_DOC_ID]); } } if (spilledVertexIdSet.Any()) { const string NODE_ALISE = "Node"; JsonQuery query = new JsonQuery { NodeAlias = NODE_ALISE }; query.AddSelectElement("*"); query.RawWhereClause = new WInPredicate(new WColumnReferenceExpression(NODE_ALISE, "id"), spilledVertexIdSet.ToList()); if (spilledVertexPartitionSet.Any()) { query.WhereConjunction( new WInPredicate( new WValueExpression($"{NODE_ALISE}{this.Connection.GetPartitionPathIndexer()}"), spilledVertexPartitionSet.ToList()), BooleanBinaryExpressionType.And); } // TODO: remove this code when you understand it. // string idInClause = string.Join(", ", spilledVertexIdSet.Select(id => $"'{id}'")); // string partitionInClause = string.Join(", ", spilledVertexPartitionSet.Select(partition => $"'{partition}'")); // string queryScript = $"SELECT * FROM Node WHERE Node.id IN ({idInClause})" + // (string.IsNullOrEmpty(partitionInClause) // ? "" // : $" AND Node{this.Connection.GetPartitionPathIndexer()} IN ({partitionInClause})"); // IEnumerable<dynamic> spilledVertices = this.Connection.ExecuteDocDbQuery(queryScript); IEnumerable <JObject> spilledVertices = this.ExecuteQueryScript(query); foreach (JObject vertex in spilledVertices) { JObject vertexObject = vertex; string vertexId = (string)vertexObject[DocumentDBKeywords.KW_DOC_ID]; VertexField vertexField = command.VertexCache.AddOrUpdateVertexField(vertexId, vertexObject); vertexField.ConstructPartialLazyAdjacencyList(vertexIdAndEdgeObjectsDict[vertexId], false); } } foreach (KeyValuePair <string, List <string> > pair in vertexIdAndEdgeIdsDict) { string vertexId = pair.Key; List <string> edgeIds = pair.Value; VertexField vertexField = command.VertexCache.GetVertexField(vertexId); foreach (string edgeId in edgeIds) { RawRecord nodeRecord = new RawRecord(); // // Fill node property field // foreach (string propertyName in nodeProperties) { FieldObject propertyValue = vertexField[propertyName]; nodeRecord.Append(propertyValue); } RawRecord edgeRecord = new RawRecord(edgeProperties.Count); EdgeField edgeField = vertexField.AdjacencyList.GetEdgeField(edgeId, false); Debug.Assert(edgeField != null, "edgeField != null"); string startVertexId = vertexField.VertexId; AdjacencyListDecoder.FillMetaField(edgeRecord, edgeField, startVertexId, vertexField.Partition, true, false); AdjacencyListDecoder.FillPropertyField(edgeRecord, edgeField, edgeProperties); nodeRecord.Append(edgeRecord); yield return(nodeRecord); } } }
internal override List <RawRecord> CrossApply(RawRecord record) { var results = new List <RawRecord>(); // Extract all properties if allPropertyIndex >= 0 if (allPropertyIndex >= 0 && record[allPropertyIndex] != null) { VertexField vertexField = record[allPropertyIndex] as VertexField; if (vertexField != null) { foreach (PropertyField property in vertexField.AllProperties) { string propertyName = property.PropertyName; switch (propertyName) { // Reversed properties for meta-data case "_edge": case "_partition": case "_reverse_edge": case "_nextEdgeOffset": case "_rid": case "_self": case "_etag": case "_attachments": case "_ts": continue; default: RawRecord r = new RawRecord(); if (property is VertexSinglePropertyField || property is ValuePropertyField) { r.Append(property); } else if (property is VertexPropertyField) { foreach (VertexSinglePropertyField p in ((VertexPropertyField)property).Multiples.Values) { r.Append(p); } } else { Debug.Assert(false, $"[PropertiesOperator.CrossApply] property type error: {property.GetType()}"); } results.Add(r); break; } } } else { EdgeField edgeField = record[allPropertyIndex] as EdgeField; if (edgeField == null) { throw new GraphViewException( string.Format("The FieldObject record[{0}] should be a VertexField or EdgeField but now it is {1}.", allPropertyIndex, record[allPropertyIndex].ToString())); } foreach (var propertyPair in edgeField.EdgeProperties) { string propertyName = propertyPair.Key; EdgePropertyField propertyField = propertyPair.Value; switch (propertyName) { // Reversed properties for meta-data case "_offset": case "_srcV": case "_sinkV": case "_srcVLabel": case "_sinkVLabel": continue; default: RawRecord r = new RawRecord(); r.Append(propertyField); results.Add(r); break; } } } } else { // TODO: Now translation code needn't to generate the key name for the operator foreach (var pair in propertyList) { //string propertyName = pair.Item1; int propertyValueIndex = pair.Item2; var propertyValue = record[propertyValueIndex]; if (propertyValue == null) { continue; } var result = new RawRecord(); result.Append(propertyValue); results.Add(result); } } return(results); }
internal override List <RawRecord> CrossApply(RawRecord record) { var results = new List <RawRecord>(); // Extract all values if allValuesIndex >= 0 if (allValuesIndex >= 0 && record[allValuesIndex] != null) { VertexField vertexField = record[allValuesIndex] as VertexField; if (vertexField != null) { foreach (PropertyField property in vertexField.AllProperties) { string propertyName = property.PropertyName; switch (propertyName) { // Reversed properties for meta-data case "_edge": case "_reverse_edge": case "_partition": case "_nextEdgeOffset": case "_rid": case "_self": case "_etag": case "_attachments": case "_ts": continue; default: RawRecord r = new RawRecord(); r.Append(new StringField(property.PropertyValue, property.JsonDataType)); results.Add(r); break; } } } else { EdgeField edgeField = record[allValuesIndex] as EdgeField; if (edgeField == null) { throw new GraphViewException( string.Format("The FieldObject record[{0}] should be a VertexField or EdgeField but now it is {1}.", allValuesIndex, record[allValuesIndex].ToString())); } foreach (var propertyPair in edgeField.EdgeProperties) { string propertyName = propertyPair.Key; EdgePropertyField propertyField = propertyPair.Value; switch (propertyName) { // Reversed properties for meta-data case "_offset": case "_srcV": case "_srcVLabel": case "_sinkV": case "_sinkVLabel": continue; default: RawRecord r = new RawRecord(); r.Append(new StringField(propertyField.ToValue, propertyField.JsonDataType)); results.Add(r); break; } } } } else { foreach (var propIdx in ValuesIdxList) { PropertyField propertyValue = record[propIdx] as PropertyField; if (propertyValue == null) { continue; } var result = new RawRecord(); result.Append(new StringField(propertyValue.ToValue, propertyValue.JsonDataType)); results.Add(result); } } return(results); }
internal override List <RawRecord> CrossApply(RawRecord record) { List <RawRecord> results = new List <RawRecord>(); FieldObject inputTarget = record[this.inputTargetIndex]; if (inputTarget is VertexField) { VertexField vertexField = (VertexField)inputTarget; foreach (VertexPropertyField property in vertexField.VertexProperties.Values) { string propertyName = property.PropertyName; Debug.Assert(!VertexField.IsVertexMetaProperty(propertyName)); Debug.Assert(propertyName == "_edge"); Debug.Assert(propertyName == "_reverse_edge"); switch (propertyName) { case "_rid": case "_self": case "_etag": case "_attachments": case "_ts": continue; default: foreach (VertexSinglePropertyField singleVp in property.Multiples.Values) { RawRecord r = new RawRecord(); r.Append(new StringField(singleVp.PropertyValue, singleVp.JsonDataType)); results.Add(r); } break; } } } else if (inputTarget is EdgeField) { EdgeField edgeField = (EdgeField)inputTarget; foreach (KeyValuePair <string, EdgePropertyField> propertyPair in edgeField.EdgeProperties) { string propertyName = propertyPair.Key; EdgePropertyField edgePropertyField = propertyPair.Value; switch (propertyName) { // Reserved properties for meta-data case "_edgeId": case "_offset": case "_srcV": case "_sinkV": case "_srcVLabel": case "_sinkVLabel": continue; default: RawRecord r = new RawRecord(); r.Append(new StringField(edgePropertyField.PropertyValue, edgePropertyField.JsonDataType)); results.Add(r); break; } } } else if (inputTarget is VertexSinglePropertyField) { VertexSinglePropertyField singleVp = inputTarget as VertexSinglePropertyField; foreach (KeyValuePair <string, ValuePropertyField> kvp in singleVp.MetaProperties) { RawRecord r = new RawRecord(); ValuePropertyField metaPropertyField = kvp.Value; r.Append(new StringField(metaPropertyField.PropertyValue, metaPropertyField.JsonDataType)); results.Add(r); } } else { throw new GraphViewException("The input of values() cannot be a meta or edge property."); } return(results); }
internal override RawRecord DataModify(RawRecord record) { long edgeOffset = long.Parse(record[this._edgeOffsetIndex].ToValue); string srcVertexId = record[this._srcVertexIdIndex].ToValue; JObject srcVertexObject = this.Connection.RetrieveDocumentById(srcVertexId); string outEdgeDocId; JObject outEdgeObject; EdgeDocumentHelper.FindEdgeBySourceAndOffset( this.Connection, srcVertexObject, srcVertexId, edgeOffset, false, out outEdgeObject, out outEdgeDocId); if (outEdgeObject == null) { // TODO: Is there something wrong? Debug.WriteLine($"[UpdateEdgePropertiesOperator] The edge does not exist: vertexId = {srcVertexId}, edgeOffset = {edgeOffset}"); return(null); } string sinkVertexId = (string)outEdgeObject["_sinkV"]; JObject sinkVertexObject; string inEdgeDocId; JObject inEdgeObject; if (sinkVertexId.Equals(srcVertexId)) { sinkVertexObject = srcVertexObject; // NOTE: Must not use DeepClone() here! } else { sinkVertexObject = this.Connection.RetrieveDocumentById(sinkVertexId); } EdgeDocumentHelper.FindEdgeBySourceAndOffset( this.Connection, sinkVertexObject, srcVertexId, edgeOffset, true, out inEdgeObject, out inEdgeDocId); VertexField srcVertexField = this.Connection.VertexCache.GetVertexField(srcVertexId); VertexField sinkVertexField = this.Connection.VertexCache.GetVertexField(sinkVertexId); EdgeField outEdgeField = srcVertexField.AdjacencyList.GetEdgeField(srcVertexId, edgeOffset); EdgeField inEdgeField = sinkVertexField.RevAdjacencyList.GetEdgeField(srcVertexId, edgeOffset); // Drop all non-reserved properties if (this.PropertiesToBeUpdated.Count == 1 && !this.PropertiesToBeUpdated[0].Item1.SingleQuoted && this.PropertiesToBeUpdated[0].Item1.Value.Equals("*", StringComparison.OrdinalIgnoreCase) && !this.PropertiesToBeUpdated[0].Item2.SingleQuoted && this.PropertiesToBeUpdated[0].Item2.Value.Equals("null", StringComparison.OrdinalIgnoreCase)) { List <string> toBeDroppedProperties = GraphViewJsonCommand.DropAllEdgeProperties(outEdgeObject); foreach (var propertyName in toBeDroppedProperties) { outEdgeField.EdgeProperties.Remove(propertyName); } toBeDroppedProperties = GraphViewJsonCommand.DropAllEdgeProperties(inEdgeObject); foreach (var propertyName in toBeDroppedProperties) { inEdgeField.EdgeProperties.Remove(propertyName); } } else { foreach (Tuple <WValueExpression, WValueExpression, int> tuple in this.PropertiesToBeUpdated) { WValueExpression keyExpression = tuple.Item1; WValueExpression valueExpression = tuple.Item2; if (this.Mode == UpdatePropertyMode.Set) { // Modify edgeObject (update the edge property) JProperty updatedProperty = GraphViewJsonCommand.UpdateProperty(outEdgeObject, keyExpression, valueExpression); // Update VertexCache if (updatedProperty == null) { outEdgeField.EdgeProperties.Remove(keyExpression.Value); } else { outEdgeField.UpdateEdgeProperty(updatedProperty, outEdgeField); } // Modify edgeObject (update the edge property) updatedProperty = GraphViewJsonCommand.UpdateProperty(inEdgeObject, keyExpression, valueExpression); // Update VertexCache if (updatedProperty == null) { inEdgeField.EdgeProperties.Remove(keyExpression.Value); } else { inEdgeField.UpdateEdgeProperty(updatedProperty, inEdgeField); } } else { throw new NotImplementedException(); } } } // Interact with DocDB to update the property EdgeDocumentHelper.UpdateEdgeProperty(this.Connection, srcVertexObject, outEdgeDocId, false, outEdgeObject); EdgeDocumentHelper.UpdateEdgeProperty(this.Connection, sinkVertexObject, inEdgeDocId, true, inEdgeObject); // // Drop edge property // if (this.PropertiesToBeUpdated.Any(t => t.Item2 == null)) { return(null); } return(record); }