/// <summary> /// Find the matching context path that results in a single field. /// </summary> protected ContextValue CreateContextValue(Parser parser, string val, int recordNumber, params Type[] types) { ContextValue cv = parser.CreateContextValue(val, recordNumber, types); AddOrUpdate(cv); return(cv); }
protected ContextNode CreateNode(int i, Guid id, ContextValue cv, ContextNode node, Type type) { if (i == cv.TypePath.Count - 1) { // At this point, node.Children[].Type && node.Children[].ContextValue.RecordNumber must be unique! Assert.That <ContextValueDictionaryException>(!node.Children.Any(c => c.Type == type && c.ContextValue.RecordNumber == cv.RecordNumber), "ContextValue type and record number must be unique to parent context."); } ContextNode childNode = new ContextNode(id, type); node.AddChild(childNode); // Since we're creating a node, add it to the flat tree view. if (!flatView.TryGetValue(type, out List <ContextNode> nodes)) { flatView[type] = new List <ContextNode>(); } flatView[type].Add(childNode); return(childNode); }
public ContextValue CreateContextValue(string val, int recordNumber, params Type[] types) { Assert.That(types.Last().HasInterface <IValueEntity>(), "The last type in the context path must implement the IValueEntity interface."); // Clone the working list. List <FieldContextPath> matchingFieldPaths = new List <FieldContextPath>(fieldContextPaths); int n = 0; foreach (Type type in types) { // Reduce the working list down to only the matches. matchingFieldPaths = new List <FieldContextPath>(matchingFieldPaths.Where(fcp => fcp.Path[n].Type == type)); ++n; } Assert.That(matchingFieldPaths.Count == 1, "Expected a single matching field to remain."); List <Guid> instancePath = CreateInstancePath(types); ContextValue cv = matchingFieldPaths[0].Field.CreateValue(val, instancePath); cv.RecordNumber = recordNumber; return(cv); }
public void AddOrUpdate(ContextValue cv) { // We have to process this synchronously! // If async, we might get simultaneous requests (particularly from the browser's async PUT calls) to add a value. // While we're constructing the dictionary entry for one context path, another request might come in before we've // created all the nodes for the first call. lock (this) { // Walk the instance/path, creating new nodes in the context tree as required. Assert.That(cv.TypePath.Count == cv.InstancePath.Count, "type path and instance path should have the same number of entries."); ContextNode node = tree; for (int i = 0; i < cv.TypePath.Count; i++) { // Walk the tree. var(id, type) = (cv.InstancePath[i], cv.TypePath[i]); if (node.Children.TryGetSingle(c => c.InstanceId == id, out ContextNode childNode)) { node = childNode; } else { // Are we referencing an existing sub-context? if (flatView.TryGetValue(type, out List <ContextNode> nodes)) { // The instance path of the node must match all the remaining instance paths in the context // we're adding/updating! bool foundExistingSubContext = false; foreach (var fvnode in nodes) { foreach (var fvnodepath in fvnode.ChildInstancePaths()) { if (cv.InstancePath.Skip(i).SequenceEqual(fvnodepath)) { // This node get's a child referencing the existing sub-context node. node.AddChild(fvnode); node = fvnode; foundExistingSubContext = true; break; } } if (foundExistingSubContext) { break; } } if (!foundExistingSubContext) { node = CreateNode(i, id, cv, node, type); } } else { node = CreateNode(i, id, cv, node, type); } } } // The last entry in the tree gets the actual context value. We've either added this node to the tree // or updating an existing node. node.ContextValue = cv; } }