/// <summary> /// Constructor to create a new navigation link scope. /// </summary> /// <param name="writerState">The writer state for the new scope.</param> /// <param name="navLink">The navigation link for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> internal NavigationLinkScope(WriterState writerState, ODataNavigationLink navLink, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) : base(writerState, navLink, navigationSource, entityType, skipWriting, selectedProperties, odataUri) { }
/// <summary> /// Create a new entry scope. /// </summary> /// <param name="entry">The entry for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <returns>The newly create scope.</returns> protected abstract EntryScope CreateEntryScope(ODataEntry entry, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri);
/// <summary> /// Constructor to create a new feed scope. /// </summary> /// <param name="feed">The feed for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> internal FeedScope(ODataFeed feed, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) : base(WriterState.Feed, feed, navigationSource, entityType, skipWriting, selectedProperties, odataUri) { this.serializationInfo = feed.SerializationInfo; }
/// <summary> /// Constructor to create a new entry scope. /// </summary> /// <param name="entry">The entry for the new scope.</param> /// <param name="serializationInfo">The serialization info for the current entry.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="writingResponse">true if we are writing a response, false if it's a request.</param> /// <param name="writerBehavior">The <see cref="ODataWriterBehavior"/> instance controlling the behavior of the writer.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <param name="enableValidation">Enable validation or not.</param> internal EntryScope(ODataEntry entry, ODataFeedAndEntrySerializationInfo serializationInfo, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, bool writingResponse, ODataWriterBehavior writerBehavior, SelectedPropertiesNode selectedProperties, ODataUri odataUri, bool enableValidation = true) : base(WriterState.Entry, entry, navigationSource, entityType, skipWriting, selectedProperties, odataUri) { Debug.Assert(writerBehavior != null, "writerBehavior != null"); if (entry != null) { this.duplicatePropertyNamesChecker = new DuplicatePropertyNamesChecker(writerBehavior.AllowDuplicatePropertyNames, writingResponse, !enableValidation); } this.serializationInfo = serializationInfo; }
private void PushScope(WriterState state, ODataItem item, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { Debug.Assert( state == WriterState.Error || state == WriterState.Entry && (item == null || item is ODataEntry) || state == WriterState.Feed && item is ODataFeed || state == WriterState.NavigationLink && item is ODataNavigationLink || state == WriterState.NavigationLinkWithContent && item is ODataNavigationLink || state == WriterState.Start && item == null || state == WriterState.Completed && item == null, "Writer state and associated item do not match."); Scope scope; switch (state) { case WriterState.Entry: scope = this.CreateEntryScope((ODataEntry)item, navigationSource, entityType, skipWriting, selectedProperties, odataUri); break; case WriterState.Feed: scope = this.CreateFeedScope((ODataFeed)item, navigationSource, entityType, skipWriting, selectedProperties, odataUri); break; case WriterState.NavigationLink: // fall through case WriterState.NavigationLinkWithContent: scope = this.CreateNavigationLinkScope(state, (ODataNavigationLink)item, navigationSource, entityType, skipWriting, selectedProperties, odataUri); break; case WriterState.Start: // fall through case WriterState.Completed: // fall through case WriterState.Error: scope = new Scope(state, item, navigationSource, entityType, skipWriting, selectedProperties, odataUri); break; default: string errorMessage = Strings.General_InternalError(InternalErrorCodes.ODataWriterCore_Scope_Create_UnreachableCodePath); Debug.Assert(false, errorMessage); throw new ODataException(errorMessage); } this.scopes.Push(scope); }
/// <summary> /// Constructor creating a new writer scope. /// </summary> /// <param name="state">The writer state of this scope.</param> /// <param name="item">The item attached to this scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of this scope should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> internal Scope(WriterState state, ODataItem item, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { this.state = state; this.item = item; this.entityType = entityType; this.navigationSource = navigationSource; this.skipWriting = skipWriting; this.selectedProperties = selectedProperties; this.odataUri = odataUri; }
private void VerifyCombination(SelectedPropertiesNode left, SelectedPropertiesNode right, Action<SelectedPropertiesNode> verify) { var result = SelectedPropertiesNode.CombineNodes(left, right); verify(result); result = SelectedPropertiesNode.CombineNodes(right, left); verify(result); }
private void AddMissingOperationsForAll(SelectedPropertiesNode selectedProperties) { AddMissingOperations(this.entry, this.entityType, selectedProperties, this.model, type => this.allOperations, entry => new NoOpEntityMetadataBuilder(entry), e => false); }
/// <summary>Process sub expand node, set name for the node.</summary> /// <param name="nodeName">Node name for the subexpandnode.</param> /// <param name="subExpandNode">Generated sub expand node.</param> /// <returns>The sub expanded node passed in.</returns> private static SelectedPropertiesNode ProcessSubExpand(string nodeName, SelectedPropertiesNode subExpandNode) { if (subExpandNode != null) { subExpandNode.nodeName = nodeName; } return subExpandNode; }
/// <summary>Create SelectedPropertiesNode using selected name list and expand node list.</summary> /// <param name="selectList">A list of selected item names.</param> /// <param name="expandList">A list of sub expanded nodes.</param> /// <returns>The generated SelectedPropertiesNode.</returns> private static SelectedPropertiesNode CombineSelectAndExpandResult(IList<string> selectList, IList<SelectedPropertiesNode> expandList) { List<string> rawSelect = selectList.ToList(); rawSelect.RemoveAll(expandList.Select(m => m.nodeName).Contains); SelectedPropertiesNode node = new SelectedPropertiesNode(SelectionType.PartialSubtree) { selectedProperties = CreateSelectedPropertiesHashSet(), children = new Dictionary<string, SelectedPropertiesNode>(StringComparer.Ordinal) }; foreach (string selectItem in rawSelect) { if (ProjectedPropertiesAnnotation.StarSegment == selectItem) { node.hasWildcard = true; } else { node.selectedProperties.Add(selectItem); } } foreach (var expandItem in expandList) { node.children[expandItem.nodeName] = expandItem; } return node; }
/// <summary> /// Ensures that a child annotation for the specified segment name already exists; if not creates one. /// </summary> /// <param name="segmentName">The segment name to get the child annotation for.</param> /// <returns>The existing or newly created child annotation for the <paramref name="segmentName"/>.</returns> private SelectedPropertiesNode EnsureChildAnnotation(string segmentName) { Debug.Assert(segmentName != null, "segmentName != null"); if (this.children == null) { this.children = new Dictionary<string, SelectedPropertiesNode>(StringComparer.Ordinal); } SelectedPropertiesNode childNode; if (!this.children.TryGetValue(segmentName, out childNode)) { childNode = new SelectedPropertiesNode(SelectionType.PartialSubtree); this.children.Add(segmentName, childNode); } return childNode; }
/// <summary> /// Recursively combines the left and right nodes. Used when there are type segments present in the select paths which /// causes there to be multiple children for the same property/navigation. /// </summary> /// <param name="left">The left node.</param> /// <param name="right">The right node.</param> /// <returns>The combined node.</returns> internal static SelectedPropertiesNode CombineNodes(SelectedPropertiesNode left, SelectedPropertiesNode right) { Debug.Assert(left != null, "left != null"); Debug.Assert(right != null, "right != null"); // if either one includes the entire subtree, then so does the result if (left.selectionType == SelectionType.EntireSubtree || right.selectionType == SelectionType.EntireSubtree) { return EntireSubtree; } // if the left hand side is empty, then use the right hand side if (left.selectionType == SelectionType.Empty) { // even if this is empty too, this all works return right; } // likewise, if the right hand side is empty, use the left if (right.selectionType == SelectionType.Empty) { return left; } Debug.Assert(left.selectionType == SelectionType.PartialSubtree, "left.selectionType == SelectionType.PartialSubtree"); Debug.Assert(right.selectionType == SelectionType.PartialSubtree, "right.selectionType == SelectionType.PartialSubtree"); var combined = new SelectedPropertiesNode(SelectionType.PartialSubtree) { hasWildcard = left.hasWildcard | right.hasWildcard }; // copy over selected properties, combining as needed if (left.selectedProperties != null && right.selectedProperties != null) { combined.selectedProperties = CreateSelectedPropertiesHashSet(left.selectedProperties.AsEnumerable().Concat(right.selectedProperties)); } else if (left.selectedProperties != null) { combined.selectedProperties = CreateSelectedPropertiesHashSet(left.selectedProperties); } else if (right.selectedProperties != null) { combined.selectedProperties = CreateSelectedPropertiesHashSet(right.selectedProperties); } // copy over children, combining as needed if (left.children != null && right.children != null) { combined.children = new Dictionary<string, SelectedPropertiesNode>(left.children); foreach (var child in right.children) { SelectedPropertiesNode fromLeft; if (combined.children.TryGetValue(child.Key, out fromLeft)) { combined.children[child.Key] = CombineNodes(fromLeft, child.Value); } else { combined.children[child.Key] = child.Value; } } } else if (left.children != null) { combined.children = new Dictionary<string, SelectedPropertiesNode>(left.children); } else if (right.children != null) { combined.children = new Dictionary<string, SelectedPropertiesNode>(right.children); } return combined; }
private static void AddMissingOperations(ODataEntry entry, IEdmEntityType entityType, SelectedPropertiesNode selectedProperties, IEdmModel model, Func<IEdmType, IEdmOperation[]> getOperations, Func<ODataEntry, ODataEntityMetadataBuilder> getEntityMetadataBuilder = null, Func<IEdmEntityType, bool> typeIsOpen = null) { var metadataContext = new TestMetadataContext { GetModelFunc = () => model, GetMetadataDocumentUriFunc = () => new Uri("http://temp.org/$metadata"), GetServiceBaseUriFunc = () => new Uri("http://temp.org/"), GetBindableOperationsForTypeFunc = getOperations, GetEntityMetadataBuilderFunc = getEntityMetadataBuilder, OperationsBoundToEntityTypeMustBeContainerQualifiedFunc = typeIsOpen, }; var entryContext = ODataEntryMetadataContext.Create(entry, new TestFeedAndEntryTypeContext(), /*serializationInfo*/null, entityType, metadataContext, selectedProperties); var generator = new ODataMissingOperationGenerator(entryContext, metadataContext); List<ODataAction> actions = generator.GetComputedActions().ToList(); List<ODataFunction> functions = generator.GetComputedFunctions().ToList(); actions.ForEach(entry.AddAction); functions.ForEach(entry.AddFunction); }
/// <summary> /// Creates a new navigation link scope. /// </summary> /// <param name="writerState">The writer state for the new scope.</param> /// <param name="navLink">The navigation link for the new scope.</param> /// <param name="navigationSource">The navigation source we are going to write entities for.</param> /// <param name="entityType">The entity type for the entries in the feed to be written (or null if the entity set base type should be used).</param> /// <param name="skipWriting">true if the content of the scope to create should not be written.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> /// <param name="odataUri">The ODataUri info of this scope.</param> /// <returns>The newly created navigation link scope.</returns> protected virtual NavigationLinkScope CreateNavigationLinkScope(WriterState writerState, ODataNavigationLink navLink, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { return new NavigationLinkScope(writerState, navLink, navigationSource, entityType, skipWriting, selectedProperties, odataUri); }
internal SelectedPropertiesNodeAssertions(SelectedPropertiesNode node) : base(node) { }
/// <summary> /// Place where derived writers can perform custom steps before the entry is writen, at the begining of WriteStartEntryImplementation. /// </summary> /// <param name="entry">Entry to write.</param> /// <param name="typeContext">The context object to answer basic questions regarding the type of the entry or feed.</param> /// <param name="selectedProperties">The selected properties of this scope.</param> protected virtual void PrepareEntryForWriteStart(ODataEntry entry, ODataFeedAndEntryTypeContext typeContext, SelectedPropertiesNode selectedProperties) { // No-op Atom and Verbose JSON. The JSON Light writer will override this method and inject the appropriate metadata builder // into the entry before writing. // When we support AutoComputePayloadMetadata for all formats in the future, we can inject the metadata builder in here and // remove virtual from this method. }
protected override ODataWriterCore.EntryScope CreateEntryScope(ODataEntry entry, IEdmNavigationSource navigationSource, IEdmEntityType entityType, bool skipWriting, SelectedPropertiesNode selectedProperties, ODataUri odataUri) { throw new NotImplementedException(); }