/// <summary> /// Process a <see cref="SelectTermToken"/> to identify whether it's a Wildcard path. /// </summary> /// <param name="selectToken">the select token to process.</param> /// <param name="newSelectItem">the built select item to out.</param> private bool ProcessWildcardTokenPath(SelectTermToken selectToken, out SelectItem newSelectItem) { newSelectItem = null; if (selectToken == null || selectToken.PathToProperty == null) { return(false); } PathSegmentToken pathToken = selectToken.PathToProperty; if (SelectPathSegmentTokenBinder.TryBindAsWildcard(pathToken, this.Model, out newSelectItem)) { // * or Namespace.* if (pathToken.NextToken != null) { throw new ODataException(ODataErrorStrings.SelectExpandBinder_InvalidIdentifierAfterWildcard(pathToken.NextToken.Identifier)); } VerifyNoQueryOptionsNested(selectToken, pathToken.Identifier); return(true); } return(false); }
/// <summary> /// Add a select item to the current list of selection items /// </summary> /// <param name="itemToAdd">The item to add</param> internal void AddToSelectedItems(SelectItem itemToAdd) { ExceptionUtils.CheckArgumentNotNull(itemToAdd, "itemToAdd"); if (this.selectedItems.Any(x => x is WildcardSelectItem) && IsStructuralOrNavigationPropertySelectionItem(itemToAdd)) { return; } bool isWildcard = itemToAdd is WildcardSelectItem; List <SelectItem> newSelectedItems = new List <SelectItem>(); foreach (SelectItem selectedItem in this.selectedItems) { if (isWildcard) { if (!IsStructuralSelectionItem(selectedItem)) { newSelectedItems.Add(selectedItem); } } else { newSelectedItems.Add(selectedItem); } } newSelectedItems.Add(itemToAdd); this.selectedItems = new ReadOnlyCollection <SelectItem>(newSelectedItems); }
/// <summary> /// Bind the $expand <see cref="ExpandToken"/> and $select <see cref="SelectToken"/> at this level. /// </summary> /// <param name="expandToken">the expand token to visit.</param> /// <param name="selectToken">the select token to visit.</param> /// <returns>a SelectExpand clause based on <see cref="ExpandToken"/> and <see cref="SelectToken"/>.</returns> public SelectExpandClause Bind(ExpandToken expandToken, SelectToken selectToken) { List <SelectItem> selectExpandItems = new List <SelectItem>(); // $expand= if (expandToken != null && expandToken.ExpandTerms.Any()) { selectExpandItems.AddRange(expandToken.ExpandTerms.Select(this.GenerateExpandItem).Where(s => s != null)); } // $select= bool isAllSelected = true; if (selectToken != null && selectToken.SelectTerms.Any()) { // if there are any select items at this level then allSelected is false, otherwise it's true. isAllSelected = false; foreach (SelectTermToken selectTermToken in selectToken.SelectTerms) { SelectItem selectItem = GenerateSelectItem(selectTermToken); PathSelectItem selectPathItem = selectItem as PathSelectItem; bool duplicate = false; if (selectPathItem != null) { // It's not allowed to have multiple select clause with the same path. // For example: $select=abc($top=2),abc($skip=2) is not allowed by design. // Customer should combine them together, for example: $select=abc($top=2;$skip=2). // The logic is different with ExpandTreeNormalizer. We should change the logic in ExpandTreeNormalizer // in next breaking change version. // For backward compatibility with previous versions of OData Library, we only validate // if one of the select items has options. foreach (PathSelectItem existingItem in selectExpandItems.OfType <PathSelectItem>()) { if ((selectPathItem.HasOptions && overLaps(selectPathItem, existingItem)) || (existingItem.HasOptions && overLaps(existingItem, selectPathItem))) { throw new ODataException(ODataErrorStrings.SelectTreeNormalizer_MultipleSelecTermWithSamePathFound(ToPathString(selectTermToken.PathToProperty))); } // two items without options are identical -- for backward compat just ignore the new one if (selectPathItem.SelectedPath.Equals(existingItem.SelectedPath)) { duplicate = true; } } } if (!duplicate) { AddToSelectedItems(selectItem, selectExpandItems); } } } // It's better to return "null" if both expand and select are null. // However, in order to be consistent, we returns empty "SelectExpandClause" with AllSelected = true. return(new SelectExpandClause(selectExpandItems, isAllSelected)); }
private static bool IsStructuralOrNavigationPropertySelectionItem(SelectItem selectItem) { PathSelectItem pathSelectItem = selectItem as PathSelectItem; return(pathSelectItem != null && (pathSelectItem.SelectedPath.LastSegment is NavigationPropertySegment || pathSelectItem.SelectedPath.LastSegment is PropertySegment)); }
/// <summary> /// Add a select item to the current list of selection items /// </summary> /// <param name="itemToAdd">The item to add</param> /// <param name="getOnlySubset">A boolean value indicating whether to get subset only</param> internal void AddToSelectedItems(SelectItem itemToAdd, bool getOnlySubset = false) { ExceptionUtils.CheckArgumentNotNull(itemToAdd, "itemToAdd"); WildcardSelectItem wildcardSelectItem = this.selectedItems.OfType <WildcardSelectItem>().FirstOrDefault(); if (wildcardSelectItem != null && IsStructuralOrNavigationPropertySelectionItem(itemToAdd)) { wildcardSelectItem.AddSubsumed(itemToAdd); return; } wildcardSelectItem = itemToAdd as WildcardSelectItem; if (wildcardSelectItem != null) { List <SelectItem> newSelectedItems = new List <SelectItem>(); foreach (SelectItem selectedItem in this.selectedItems) { if (!IsStructuralSelectionItem(selectedItem)) { newSelectedItems.Add(selectedItem); } else if (getOnlySubset) { var pathItem = selectedItem as PathSelectItem; if (pathItem != null && pathItem.SelectAndExpand != null) { newSelectedItems.Add(selectedItem); } else { wildcardSelectItem.AddSubsumed(selectedItem); } } else { wildcardSelectItem.AddSubsumed(selectedItem); } } this.selectedItems = newSelectedItems; } this.selectedItems.Add(itemToAdd); }
private static void AddToSelectedItems(SelectItem itemToAdd, List <SelectItem> selectItems) { if (itemToAdd == null) { return; } // ignore all property selection if there's a wildcard select item. WildcardSelectItem wildcardSelectItem = selectItems.OfType <WildcardSelectItem>().FirstOrDefault(); if (wildcardSelectItem != null && IsStructuralOrNavigationPropertySelectionItem(itemToAdd)) { wildcardSelectItem.AddSubsumed(itemToAdd); return; } // if the selected item is a nav prop, then see if its already there before we add it. PathSelectItem pathSelectItem = itemToAdd as PathSelectItem; if (pathSelectItem != null) { NavigationPropertySegment trailingNavPropSegment = pathSelectItem.SelectedPath.LastSegment as NavigationPropertySegment; if (trailingNavPropSegment != null) { if (selectItems.OfType <PathSelectItem>().Any(i => i.SelectedPath.Equals(pathSelectItem.SelectedPath))) { return; } } } // if the selected item is "*", filter the existing property selection. wildcardSelectItem = itemToAdd as WildcardSelectItem; if (wildcardSelectItem != null) { List <SelectItem> shouldFilter = selectItems.Where(s => IsStructuralSelectionItem(s)).ToList(); wildcardSelectItem.AddSubsumed(shouldFilter); foreach (var filterItem in shouldFilter) { selectItems.Remove(filterItem); } } selectItems.Add(itemToAdd); }
/// <summary> /// Add a select item to the current list of selection items /// </summary> /// <param name="itemToAdd">The item to add</param> internal void AddToSelectedItems(SelectItem itemToAdd, bool getOnlySubset = false) { ExceptionUtils.CheckArgumentNotNull(itemToAdd, "itemToAdd"); if (this.selectedItems.Any(x => x is WildcardSelectItem) && IsStructuralOrNavigationPropertySelectionItem(itemToAdd)) { return; } bool isWildcard = itemToAdd is WildcardSelectItem; List <SelectItem> newSelectedItems = new List <SelectItem>(); foreach (SelectItem selectedItem in this.selectedItems) { if (isWildcard) { if (!IsStructuralSelectionItem(selectedItem)) { newSelectedItems.Add(selectedItem); } else if (getOnlySubset) { var pathItem = selectedItem as PathSelectItem; if (pathItem != null && pathItem.SelectAndExpand != null) { newSelectedItems.Add(selectedItem); } } } else { newSelectedItems.Add(selectedItem); } } newSelectedItems.Add(itemToAdd); this.selectedItems = new ReadOnlyCollection <SelectItem>(newSelectedItems); }
/// <summary> /// Get the string representation of a select item (that isn't an expandedNavPropSelectItem /// </summary> /// <param name="selectedItem">the select item to translate</param> /// <returns>the string representation of this select item, or null if the select item is an expandedNavPropSelectItem</returns> private static string GetSelectString(SelectItem selectedItem) { WildcardSelectItem wildcardSelect = selectedItem as WildcardSelectItem; NamespaceQualifiedWildcardSelectItem namespaceQualifiedWildcard = selectedItem as NamespaceQualifiedWildcardSelectItem; PathSelectItem pathSelectItem = selectedItem as PathSelectItem; if (wildcardSelect != null) { return("*"); } else if (namespaceQualifiedWildcard != null) { return(namespaceQualifiedWildcard.Namespace + ".*"); } else if (pathSelectItem != null) { return(String.Join("/", pathSelectItem.SelectedPath.WalkWith(PathSegmentToStringTranslator.Instance).ToArray())); } else { return(null); } }
/// <summary> /// Build a wildcard selection item /// </summary> /// <param name="tokenIn">the token to bind to a wildcard</param> /// <param name="model">the model to search for this wildcard</param> /// <param name="item">the new wildcard selection item, if we found one</param> /// <returns>true if we successfully bound to a wildcard, false otherwise</returns> public static bool TryBindAsWildcard(PathSegmentToken tokenIn, IEdmModel model, out SelectItem item) { bool isTypeToken = tokenIn.IsNamespaceOrContainerQualified(); bool wildcard = tokenIn.Identifier.EndsWith("*", StringComparison.Ordinal); if (isTypeToken && wildcard) { string namespaceName = tokenIn.Identifier.Substring(0, tokenIn.Identifier.Length - 2); if (model.DeclaredNamespaces.Any(declaredNamespace => declaredNamespace.Equals(namespaceName, StringComparison.Ordinal))) { item = new NamespaceQualifiedWildcardSelectItem(namespaceName); return(true); } } if (tokenIn.Identifier == "*") { item = new WildcardSelectItem(); return(true); } item = null; return(false); }
/// <summary> /// Adds the provided <see cref="SelectItem"/> to the set of items that are replaced by the wildcard. /// </summary> internal void AddSubsumed(SelectItem selectItem) { this.subsumedSelectItems.Add(selectItem); }