/// <summary> /// Write the property access token as URI part to this builder. /// </summary> /// <param name="propertyAccess">To write as URI part.</param> protected virtual void WritePropertyAccess(PropertyAccessQueryToken propertyAccess) { ExceptionUtils.CheckArgumentNotNull(propertyAccess, "propertyAccess"); if (propertyAccess.Parent != null) { this.WriteQuery(propertyAccess.Parent); this.builder.Append(ExpressionConstants.SymbolForwardSlash); } this.builder.Append(propertyAccess.Name); }
/// <summary> /// Binds a property access token. /// </summary> /// <param name="propertyAccessToken">The property access token to bind.</param> /// <returns>The bound property access token.</returns> protected virtual QueryNode BindPropertyAccess(PropertyAccessQueryToken propertyAccessToken) { ExceptionUtils.CheckArgumentNotNull(propertyAccessToken, "propertyAccessToken"); ExceptionUtils.CheckArgumentStringNotNullOrEmpty(propertyAccessToken.Name, "propertyAccessToken.Name"); SingleValueQueryNode parentNode; SingleValueQueryNode navigationPath = null; // Set the parentNode (get the parent type, so you can check whether the Name inside propertyAccessToken really is legit offshoot of the parent type) QueryNode parent = null; if (propertyAccessToken.Parent == null) { if (this.parameter == null) { throw new ODataException(Strings.MetadataBinder_PropertyAccessWithoutParentParameter); } parentNode = this.parameter; parent = this.parameter; } else { parent = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode; if (parent == null) { throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(propertyAccessToken.Name)); } NavigationPropertyNode parentNav = parent as NavigationPropertyNode; CastNode parentCast = parent as CastNode; PropertyAccessQueryNode parentProperty = parent as PropertyAccessQueryNode; if (parentProperty != null) { navigationPath = parentProperty; var propertyPath = (IEdmStructuralProperty)parentProperty.Property; parentNode = new ParameterQueryNode() { ParameterType = propertyPath.Type }; } else if (parentCast != null) { IEdmType entityType = parentCast.EdmType; parentNode = new ParameterQueryNode() { ParameterType = entityType.ToTypeReference() }; } else if (parentNav != null) { navigationPath = parentNav; IEdmEntityType entityType = parentNav.NavigationProperty.ToEntityType(); parentNode = new ParameterQueryNode() { ParameterType = new EdmEntityTypeReference(entityType, true) }; } else { parentNode = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode; } } // Now that we have the parent type, can find its corresponding EDM type IEdmStructuredTypeReference structuredParentType = parentNode.TypeReference == null ? null : parentNode.TypeReference.AsStructuredOrNull(); IEdmProperty property = structuredParentType == null ? null : structuredParentType.FindProperty(propertyAccessToken.Name); if (property != null) { // TODO: Check that we have entity set once we add the entity set propagation into the bound tree // See RequestQueryParser.ExpressionParser.ParseMemberAccess if (property.Type.IsNonEntityODataCollectionTypeKind()) { throw new ODataException(Strings.MetadataBinder_MultiValuePropertyNotSupportedInExpression(property.Name)); } if (property.PropertyKind == EdmPropertyKind.Navigation) { // TODO: Implement navigations throw new NotImplementedException(); } if (navigationPath != null) { parentNode = navigationPath; } return new PropertyAccessQueryNode() { Source = (SingleValueQueryNode)parent, Property = property }; } else { if (parentNode.TypeReference != null && !parentNode.TypeReference.Definition.IsOpenType()) { throw new ODataException(Strings.MetadataBinder_PropertyNotDeclared(parentNode.TypeReference.ODataFullName(), propertyAccessToken.Name)); } // TODO: Implement open property support throw new NotImplementedException(); } }
/// <summary> /// Binds a property access token. /// </summary> /// <param name="propertyAccessToken">The property access token to bind.</param> /// <returns>The bound property access token.</returns> protected virtual QueryNode BindPropertyAccess(PropertyAccessQueryToken propertyAccessToken) { ExceptionUtils.CheckArgumentNotNull(propertyAccessToken, "propertyAccessToken"); ExceptionUtils.CheckArgumentStringNotNullOrEmpty(propertyAccessToken.Name, "propertyAccessToken.Name"); SingleValueQueryNode parentNode; if (propertyAccessToken.Parent == null) { if (this.parameter == null) { throw new ODataException(Strings.MetadataBinder_PropertyAccessWithoutParentParameter); } parentNode = this.parameter; } else { // TODO: Do we really want to fail with cast exception if the parent is a collection (for example)? parentNode = this.Bind(propertyAccessToken.Parent) as SingleValueQueryNode; if (parentNode == null) { throw new ODataException(Strings.MetadataBinder_PropertyAccessSourceNotSingleValue(propertyAccessToken.Name)); } } ResourceProperty property = parentNode.ResourceType == null ? null : parentNode.ResourceType.TryResolvePropertyName(propertyAccessToken.Name); if (property != null) { // TODO: Check that we have resourceset once we add the resource set propagation into the bound tree // See RequestQueryParser.ExpressionParser.ParseMemberAccess if (property.Kind == ResourcePropertyKind.MultiValue) { throw new ODataException(Strings.MetadataBinder_MultiValuePropertyNotSupportedInExpression(property.Name)); } if (property.Kind == ResourcePropertyKind.ResourceReference || property.Kind == ResourcePropertyKind.ResourceSetReference) { // TODO: Implement navigations throw new NotImplementedException(); } return new PropertyAccessQueryNode() { Source = parentNode, Property = property }; } else { if (parentNode.ResourceType != null && !parentNode.ResourceType.IsOpenType) { throw new ODataException(Strings.MetadataBinder_PropertyNotDeclared(parentNode.ResourceType.FullName, propertyAccessToken.Name)); } // TODO: Implement open property support throw new NotImplementedException(); } }