Пример #1
0
        /// <summary>Tries to create a key segment for the given filter if it is non empty.</summary>
        /// <param name="previous">Segment on which to compose.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="parenthesisExpression">Parenthesis expression of segment.</param>
        /// <param name="keySegment">The key segment that was created if the key was non-empty.</param>
        /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>Whether the key was non-empty.</returns>
        internal static bool TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, string parenthesisExpression, out ODataPathSegment keySegment, bool enableUriTemplateParsing = false, ODataUriResolver resolver = null)
        {
            Debug.Assert(parenthesisExpression != null, "parenthesisExpression != null");
            Debug.Assert(previous != null, "segment!= null");

            if (resolver == null)
            {
                resolver = ODataUriResolver.Default;
            }

            if (previous.SingleResult)
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            SegmentArgumentParser key;
            if (!SegmentArgumentParser.TryParseKeysFromUri(parenthesisExpression, out key, enableUriTemplateParsing))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            // People/NS.Employees() is OK, just like People() is OK
            if (key.IsEmpty)
            {
                keySegment = null;
                return false;
            }

            keySegment = CreateKeySegment(previous, previousKeySegment, key, resolver);
            return true;
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="UnresolvedPathSegment" /> class.
        /// </summary>
        /// <param name="previous">The property being accessed by this segment.</param>
        /// <param name="segmentValue">The unresolved segment value.</param>
        public UnresolvedPathSegment(ODataPathSegment previous, string segmentValue)
            : base(previous)
        {
            if (segmentValue == null)
            {
                throw Error.ArgumentNull("segmentValue");
            }

            SegmentValue = segmentValue;
        }
Пример #3
0
        public SegmentKeyHandlerTests()
        {
            var typeWithStringKey = new EdmEntityType("NS.Foo", "TypeWithStringKey");
            var originalType = new EdmEntityType("NS.Foo", "SourceType");
            var keyProp = typeWithStringKey.AddStructuralProperty("KeyProp", EdmPrimitiveTypeKind.String);
            typeWithStringKey.AddKeys(keyProp);
            var multipleResultsWithSingleKeyNavProp = originalType.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo() { Name = "NavProp", Target = typeWithStringKey, TargetMultiplicity = EdmMultiplicity.Many });

            this.singleResultSegmentWithSingleKey = new NavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp(), null) { SingleResult = true };
            this.multipleResultSegmentWithSingleKey = new NavigationPropertySegment(multipleResultsWithSingleKeyNavProp, null) { SingleResult = false };
            this.multipleResultSegmentWithCompositeKey = new NavigationPropertySegment(HardCodedTestModel.GetPersonMyLionsNavProp(), null) { SingleResult = false };
        }
Пример #4
0
        /// <summary>
        /// Tries to handle the current segment as a key property value.
        /// </summary>
        /// <param name="segmentText">The segment text.</param>
        /// <param name="previous">The previous segment.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="urlConvention">The current url convention for the server.</param>
        /// <param name="keySegment">The key segment that was created if the segment could be interpreted as a key.</param>
        /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>Whether or not the segment was interpreted as a key.</returns>
        internal static bool TryHandleSegmentAsKey(string segmentText, ODataPathSegment previous, KeySegment previousKeySegment, UrlConvention urlConvention, out KeySegment keySegment, bool enableUriTemplateParsing = false, ODataUriResolver resolver = null)
        {
            Debug.Assert(previous != null, "previous != null");
            Debug.Assert(urlConvention != null, "urlConvention != null");

            if (resolver == null)
            {
                resolver = ODataUriResolver.Default;
            }

            keySegment = null;

            // If the current convention is not keys-as-segments, then this does not apply.
            if (!urlConvention.GenerateKeyAsSegment)
            {
                return false;
            }

            // Keys only apply to collections, so if the prior segment is already a singleton, do not treat this segment as a key.
            if (previous.SingleResult)
            {
                return false;
            }

            // System segments (ie '$count') are never keys.
            if (IsSystemSegment(segmentText))
            {
                return false;
            }

            // If the previous type is not an entity collection type
            // TODO: collapse this and SingleResult.
            IEdmEntityType targetEntityType;
            if (previous.TargetEdmType == null || !previous.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType))
            {
                return false;
            }

            // Previously KeyAsSegment only allows single key, but we can also leverage related key finder to auto fill
            // missed key value from referential constraint information, which would be done in CreateKeySegment.
            // CreateKeySegment method will check whether key properties are missing after taking in related key values.
            keySegment = CreateKeySegment(previous, previousKeySegment, SegmentArgumentParser.FromSegment(segmentText, enableUriTemplateParsing), resolver);

            return true;
        }
Пример #5
0
        private static IEdmEntityType GetTargetEntityType(ODataPathSegment segment)
        {
            Contract.Assert(segment != null);

            EntitySetSegment entitySetSegment = segment as EntitySetSegment;
            if (entitySetSegment != null)
            {
                return entitySetSegment.EntitySet.EntityType();
            }

            SingletonSegment singletonSegment = segment as SingletonSegment;
            if (singletonSegment != null)
            {
                return singletonSegment.Singleton.EntityType();
            }

            NavigationPropertySegment navigationPropertySegment = segment as NavigationPropertySegment;
            if (navigationPropertySegment != null)
            {
                return navigationPropertySegment.NavigationSource.EntityType();
            }

            return null;
        }
Пример #6
0
        private void ProcessTokenAsPath(NonSystemToken tokenIn)
        {
            Debug.Assert(tokenIn != null, "tokenIn != null");

            List <ODataPathSegment> pathSoFar        = new List <ODataPathSegment>();
            IEdmStructuredType      currentLevelType = this.edmType;

            // first, walk through all type segments in a row, converting them from tokens into segments.
            if (tokenIn.IsNamespaceOrContainerQualified())
            {
                PathSegmentToken firstNonTypeToken;
                pathSoFar.AddRange(SelectExpandPathBinder.FollowTypeSegments(tokenIn, this.model, this.maxDepth, this.resolver, ref currentLevelType, out firstNonTypeToken));
                Debug.Assert(firstNonTypeToken != null, "Did not get last token.");
                tokenIn = firstNonTypeToken as NonSystemToken;
                if (tokenIn == null)
                {
                    throw new ODataException(ODataErrorStrings.SelectPropertyVisitor_SystemTokenInSelect(firstNonTypeToken.Identifier));
                }
            }

            // next, create a segment for the first non-type segment in the path.
            ODataPathSegment lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(tokenIn, this.model, currentLevelType, resolver);

            // next, create an ODataPath and add the segments to it.
            if (lastSegment != null)
            {
                pathSoFar.Add(lastSegment);

                bool hasCollectionInPath = false;

                // try create a complex type property path.
                while (true)
                {
                    // no need to go on if the current property is not of complex type or collection of complex type.
                    currentLevelType = lastSegment.EdmType as IEdmStructuredType;
                    var collectionType = lastSegment.EdmType as IEdmCollectionType;
                    if ((currentLevelType == null || currentLevelType.TypeKind != EdmTypeKind.Complex) &&
                        (collectionType == null || collectionType.ElementType.TypeKind() != EdmTypeKind.Complex))
                    {
                        break;
                    }

                    NonSystemToken nextToken = tokenIn.NextToken as NonSystemToken;
                    if (nextToken == null)
                    {
                        break;
                    }

                    lastSegment = null;

                    // This means last segment a collection of complex type,
                    // current segment can only be type cast and cannot be proprty name.
                    if (currentLevelType == null)
                    {
                        currentLevelType    = collectionType.ElementType.Definition as IEdmStructuredType;
                        hasCollectionInPath = true;
                    }
                    else if (!hasCollectionInPath)
                    {
                        // If there is no collection type in the path yet, will try to bind property for the next token
                        // first try bind the segment as property.
                        lastSegment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(nextToken, this.model,
                                                                                                currentLevelType, resolver);
                    }

                    // then try bind the segment as type cast.
                    if (lastSegment == null)
                    {
                        IEdmStructuredType typeFromNextToken = UriEdmHelpers.FindTypeFromModel(this.model, nextToken.Identifier, this.resolver) as IEdmStructuredType;

                        if (typeFromNextToken.IsOrInheritsFrom(currentLevelType))
                        {
                            lastSegment = new TypeSegment(typeFromNextToken, /*entitySet*/ null);
                        }
                    }

                    // type cast failed too.
                    if (lastSegment == null)
                    {
                        break;
                    }

                    // try move to and add next path segment.
                    tokenIn = nextToken;
                    pathSoFar.Add(lastSegment);
                }
            }

            ODataSelectPath selectedPath = new ODataSelectPath(pathSoFar);

            var selectionItem = new PathSelectItem(selectedPath);

            // non-navigation cases do not allow further segments in $select.
            if (tokenIn.NextToken != null)
            {
                throw new ODataException(ODataErrorStrings.SelectBinder_MultiLevelPathInSelect);
            }

            // if the selected item is a nav prop, then see if its already there before we add it.
            NavigationPropertySegment trailingNavPropSegment = selectionItem.SelectedPath.LastSegment as NavigationPropertySegment;

            if (trailingNavPropSegment != null)
            {
                if (this.expandClauseToDecorate.SelectedItems.Any(x => x is PathSelectItem &&
                                                                  ((PathSelectItem)x).SelectedPath.Equals(selectedPath)))
                {
                    return;
                }
            }

            this.expandClauseToDecorate.AddToSelectedItems(selectionItem);
        }
        /// <summary>
        /// Tries to get the resource property for the given segment, if it is one of the segment types that refers to a property, a navigation, or a navigation before $ref.
        /// </summary>
        /// <param name="segment">The segment.</param>
        /// <param name="projectedProperty">The property, if the segment represented a property or navigation.</param>
        /// <returns>Whether the segment represented a property or navigation.</returns>
        private static bool TryGetPropertyFromSegment(ODataPathSegment segment, out ResourceProperty projectedProperty)
        {
            Debug.Assert(segment != null, "segment != null");

            IEdmProperty edmProperty = null;
            var propertySegment = segment as PropertySegment;
            if (propertySegment != null)
            {
                edmProperty = propertySegment.Property;
            }
            else
            {
                var navigationSegment = segment as NavigationPropertySegment;
                if (navigationSegment != null)
                {
                    edmProperty = navigationSegment.NavigationProperty;
                }
                else
                {
                    var propertyLinkSegment = segment as NavigationPropertyLinkSegment;
                    if (propertyLinkSegment != null)
                    {
                        edmProperty = propertyLinkSegment.NavigationProperty;
                    }
                }
            }

            if (edmProperty != null)
            {
                projectedProperty = ((IResourcePropertyBasedEdmProperty)edmProperty).ResourceProperty;
                Debug.Assert(projectedProperty != null, "projectedProperty != null");
                return true;
            }

            projectedProperty = null;
            return false;
        }
Пример #8
0
        /// <summary>
        /// Throws if the given segment must be a leaf, as a later segment is being created.
        /// </summary>
        /// <param name="previous">The previous segment which may need to be a leaf.</param>
        private void ThrowIfMustBeLeafSegment(ODataPathSegment previous)
        {
            OperationImportSegment operationImportSegment = previous as OperationImportSegment;
            if (operationImportSegment != null)
            {
                foreach (var operationImport in operationImportSegment.OperationImports)
                {
                    if (operationImport.IsActionImport() || (operationImport.IsFunctionImport() && !((IEdmFunctionImport)operationImport).Function.IsComposable))
                    {
                        throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_MustBeLeafSegment(previous.Identifier));
                    }
                }
            }

            OperationSegment operationSegment = previous as OperationSegment;
            if (operationSegment != null)
            {
                foreach (var operation in operationSegment.Operations)
                {
                    if (operation.IsAction() || (operation.IsFunction() && !((IEdmFunction)operation).IsComposable))
                    {
                        throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_MustBeLeafSegment(previous.Identifier));
                    }
                }
            }

            if (previous.TargetKind == RequestTargetKind.Batch                  /* $batch */
                || previous.TargetKind == RequestTargetKind.Metadata            /* $metadata */
                || previous.TargetKind == RequestTargetKind.PrimitiveValue      /* $value, see TryCreateValueSegment */
                || previous.TargetKind == RequestTargetKind.OpenPropertyValue   /* $value, see TryCreateValueSegment */
                || previous.TargetKind == RequestTargetKind.EnumValue           /* $value, see TryCreateValueSegment */
                || previous.TargetKind == RequestTargetKind.MediaResource       /* $value or Media resource, see TryCreateValueSegment/CreateNamedStreamSegment */
                || previous.TargetKind == RequestTargetKind.VoidOperation       /* service operation with void return type */
                || previous.TargetKind == RequestTargetKind.Nothing             /* Nothing targeted (e.g. PathTemplate) */)
            {
                // Nothing can come after a $metadata, $value or $batch segment.
                // Nothing can come after a service operation with void return type.
                // Nothing can come after a collection property.
                throw ExceptionUtil.ResourceNotFoundError(ODataErrorStrings.RequestUriProcessor_MustBeLeafSegment(previous.Identifier));
            }
        }
Пример #9
0
        private bool TryCreateSegmentForOperation(ODataPathSegment previousSegment, string identifier, string parenthesisExpression)
        {
            // Parse Arguments syntactically
            var bindingType = previousSegment == null ? null : previousSegment.EdmType;

            ICollection<OperationSegmentParameter> resolvedParameters;
            IEdmOperation singleOperation;
            if (!TryBindingParametersAndMatchingOperation(identifier, parenthesisExpression, bindingType, this.configuration, out resolvedParameters, out singleOperation))
            {
                return false;
            }

            if (!UriEdmHelpers.IsBindingTypeValid(bindingType))
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_OperationSegmentBoundToANonEntityType);
            }

            if (previousSegment != null && bindingType == null)
            {
                throw new ODataException(ODataErrorStrings.FunctionCallBinder_CallingFunctionOnOpenProperty(identifier));
            }

            IEdmTypeReference returnType = singleOperation.ReturnType;
            IEdmEntitySetBase targetset = null;

            if (returnType != null)
            {
                IEdmNavigationSource source = previousSegment == null ? null : previousSegment.TargetEdmNavigationSource;
                targetset = singleOperation.GetTargetEntitySet(source, this.configuration.Model);
            }

            // If previous segment is cross-referenced then we explicitly dissallow the service action call
            if (previousSegment is BatchReferenceSegment)
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_BatchedActionOnEntityCreatedInSameChangeset(identifier));
            }

            // TODO: change constructor to take single import
            ODataPathSegment segment = new OperationSegment(new[] { singleOperation }, resolvedParameters, targetset)
                {
                    Identifier = identifier
                };

            DetermineEntitySetForSegment(identifier, returnType, segment, targetset, singleOperation);

            this.parsedSegments.Add(segment);

            this.TryBindKeySegmentIfNoResolvedParametersAndParathesisValueExsts(parenthesisExpression, returnType, resolvedParameters, segment);

            return true;
        }
Пример #10
0
        private void HandleNavigationPathSegment(ODataPathSegment segment)
        {
            var navigationSegment = (NavigationPropertySegment)segment;
            var entityParameterExpression = Expression.Parameter(this.currentType);
            var navigationPropertyExpression =
                Expression.Property(entityParameterExpression, navigationSegment.NavigationProperty.Name);

            // Check whether property is null or not before further selection
            var whereExpression =
                CreateNotEqualsNullExpression(navigationPropertyExpression, entityParameterExpression);
            this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType);

            if (navigationSegment.NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
            {
                // get the element type of the target
                // (the type should be an EntityCollection<T> for navigation queries).
                this.currentType = navigationPropertyExpression.Type.GetEnumerableItemType();

                // need to explicitly define the delegate type as IEnumerable<T>
                Type delegateType = typeof(Func<,>).MakeGenericType(
                    queryable.ElementType,
                    typeof(IEnumerable<>).MakeGenericType(this.currentType));
                LambdaExpression selectBody =
                    Expression.Lambda(delegateType, navigationPropertyExpression, entityParameterExpression);

                this.queryable = ExpressionHelpers.SelectMany(this.queryable, selectBody, this.currentType);
            }
            else
            {
                this.currentType = navigationPropertyExpression.Type;
                LambdaExpression selectBody =
                    Expression.Lambda(navigationPropertyExpression, entityParameterExpression);
                this.queryable = ExpressionHelpers.Select(this.queryable, selectBody);
            }
        }
        private static bool TryBindAsDeclaredProperty(PathSegmentToken tokenIn, IEdmStructuredType edmType, ODataUriResolver resolver, out ODataPathSegment segment)
        {
            IEdmProperty prop = resolver.ResolveProperty(edmType, tokenIn.Identifier);
            if (prop == null)
            {
                segment = null;
                return false;
            }

            if (prop.PropertyKind == EdmPropertyKind.Structural)
            {
                segment = new PropertySegment((IEdmStructuralProperty)prop);
                return true;
            }

            if (prop.PropertyKind == EdmPropertyKind.Navigation)
            {
                segment = new NavigationPropertySegment((IEdmNavigationProperty)prop, null /*TODO: set*/);
                return true;
            }

            throw new ODataException(ODataErrorStrings.SelectExpandBinder_UnknownPropertyType(prop.Name));
        }
Пример #12
0
        public void FunctionNameResultsInOperationSelectionItemWithAllMatchingOverloads()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.HasDog", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetAllHasDogFunctionOverloadsForPeople() /* TODO: parameters */);
        }
Пример #13
0
 private void EmptyHandler(ODataPathSegment segment)
 {
     // Nothing will be done
 }
Пример #14
0
        public void NavPropNameResultsInNavigationPropertyLinkSelectionItem()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("MyDog", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType());

            segment.ShouldBeNavigationPropertySegment(HardCodedTestModel.GetPersonMyDogNavProp());
        }
Пример #15
0
        public void ActionNameResultsInOperationSelectionItem()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.Walk", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetDogType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetDogWalkAction());
        }
Пример #16
0
        public void PropertyNameResultsInStructuralPropertySelectionItem()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Shoe", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType());

            segment.ShouldBePropertySegment(HardCodedTestModel.GetPersonShoeProp());
        }
Пример #17
0
        public void UnfoundProperyOnOpenTypeResultsInOpenPropertySelectionItem()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.Effervescence", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPaintingType());

            segment.ShouldBeOpenPropertySegment("Fully.Qualified.Namespace.Effervescence");
        }
Пример #18
0
        public void QualifiedActionNameOnOpenTypeShouldBeInterpretedAsAnOperation()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.Restore", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPaintingType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetRestoreAction());
        }
        /// <summary>
        /// Creates the next segment.
        /// </summary>
        /// <param name="previous">The previous segment.</param>
        /// <param name="segment">The the next segment.</param>
        /// <returns>The newly created next segment.</returns>
        private SegmentInfo CreateNextSegment(SegmentInfo previous, ODataPathSegment segment)
        {
            if (segment is ValueSegment)
            {
                return CreateValueSegment(previous);
            }

            SegmentInfo segmentInfo;
            if (segment is CountSegment)
            {
                segmentInfo = CreateCountSegment(previous);

                // DEVNOTE: Prior to refactor, $count was handled alongside properties. See more detailed comment in HandleCountSegment
                Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property");
                return segmentInfo;
            }

            // if its not one of the recognized special segments, then it must be a property, type-segment, or key value.
            Debug.Assert(
                previous.TargetKind == RequestTargetKind.ComplexObject
                || previous.TargetKind == RequestTargetKind.Resource
                || previous.TargetKind == RequestTargetKind.OpenProperty
                || previous.TargetKind == RequestTargetKind.Link,
                "previous.TargetKind(" + previous.TargetKind + ") can have properties");

            CheckSegmentIsComposable(previous);

            // if the segment corresponds to a declared property, handle it
            // otherwise, fall back to type-segments, actions, and dynamic/open properties
            ResourceProperty projectedProperty;
            if (TryGetPropertyFromSegment(segment, out projectedProperty))
            {
                CheckSingleResult(previous.SingleResult, previous.Identifier);

                if (projectedProperty.IsOfKind(ResourcePropertyKind.Stream))
                {
                    segmentInfo = CreateNamedStreamSegment(previous, projectedProperty);
                    Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property");
                    return segmentInfo;
                }

                segmentInfo = this.CreatePropertySegment(previous, projectedProperty);
                Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property");
                return segmentInfo;
            }

            // If the property resolution failed, and the previous segment was targeting an entity, then we should
            // try and resolve the identifier as type name.
            SegmentInfo typeNameSegment;
            if (this.TryCreateTypeNameSegment(previous, segment, out typeNameSegment))
            {
                Debug.Assert(typeNameSegment.TargetSource == previous.TargetSource, "segment.TargetSource == previous.TargetSource");
                return typeNameSegment;
            }

            OperationWrapper serviceAction = null;
            var actionSegment = segment as OperationSegment;
            if (actionSegment != null)
            {
                Debug.Assert(actionSegment.Operations.Count() == 1, "Operation segment should only ever have exactly one operation. Was a change made to how MetadataProviderEdmModel finds actions/service operations");
                serviceAction = ((MetadataProviderEdmOperation)actionSegment.Operations.Single()).ServiceOperation;
                Debug.Assert(serviceAction != null, "serviceAction != null");
                Debug.Assert(serviceAction.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action");
            }

            if (serviceAction != null)
            {
                Debug.Assert(serviceAction.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action");

                // Service Actions can bind to a set with any ResourceSetRights except ResourceSetRights.None.
                segmentInfo = this.CreateSegmentForServiceAction(previous, serviceAction);
                Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.ServiceOperation, "segment.TargetSource == RequestTargetSource.ServiceOperation");
                return segmentInfo;
            }

            CheckSingleResult(previous.SingleResult, previous.Identifier);
            segmentInfo = CreateOpenPropertySegment(previous, ((OpenPropertySegment)segment).PropertyName);
            Debug.Assert(segmentInfo.TargetSource == RequestTargetSource.Property, "segment.TargetSource == RequestTargetSource.Property");
            return segmentInfo;
        }
Пример #20
0
        public void FunctionNameResultsInOperationSelectionItemWithOnlyOverloadsBoundToTheGivenType()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.HasDog", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetEmployeeType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetHasDogOverloadForEmployee());
        }
Пример #21
0
 private void HandleEntitySetPathSegment(ODataPathSegment segment)
 {
     var entitySetPathSegment = (EntitySetSegment)segment;
     var entitySet = entitySetPathSegment.EntitySet;
     this.queryable = this.api.GetQueryableSource(entitySet.Name, (object[])null);
     this.currentType = this.queryable.ElementType;
 }
Пример #22
0
        public void ActionNameResultsInOperationSelectionForDerivedBindingTypeItemWithAllMatchingOverloads()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.Move", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetEmployeeType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetMoveOverloadForEmployee() /* TODO: parameters */);
        }
Пример #23
0
 private void HandleValuePathSegment(ODataPathSegment segment)
 {
     this.IsValuePathSegmentPresent = true;
 }
Пример #24
0
        public void ActionNameResultsInOperationSelectionItemWithAllMatchingOverloadsMatchingBindingType()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Fully.Qualified.Namespace.Move", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPersonType());

            segment.ShouldBeOperationSegment(HardCodedTestModel.GetMoveOverloadForPerson());
        }
Пример #25
0
        // This only covers entity type cast
        // complex type cast uses ComplexCastPathSegment and is not supported by EF now
        // CLR type is got from model annotation, which means model must include that annotation.
        private void HandleEntityTypeSegment(ODataPathSegment segment)
        {
            var typeSegment = (TypeSegment)segment;
            var edmType = typeSegment.EdmType;

            if (typeSegment.EdmType.TypeKind == EdmTypeKind.Collection)
            {
                edmType = ((IEdmCollectionType)typeSegment.EdmType).ElementType.Definition;
            }

            if (edmType.TypeKind == EdmTypeKind.Entity)
            {
                this.currentType = edmType.GetClrType(api);
                this.queryable = ExpressionHelpers.OfType(this.queryable, this.currentType);
            }
        }
Пример #26
0
 /// <summary>
 /// Matches the template with an <see cref="ODataPathSegment"/>.
 /// </summary>
 /// <param name="pathSegment">The path segment to match this template with.</param>
 /// <param name="values">The dictionary of matches to be updated if the segment matches the template.</param>
 /// <returns><c>true</c> if the segment matches the template; otherwise, <c>false</c>.</returns>
 public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values)
 {
     return(pathSegment is T);
 }
Пример #27
0
        private void CreatePropertySegment(ODataPathSegment previous, IEdmProperty property, string queryPortion)
        {
            if (property.Type.IsStream())
            {
                // The server used to allow arbitrary key expressions after named streams because this check was missing.
                if (queryPortion != null)
                {
                    throw ExceptionUtil.CreateSyntaxError();
                }

                this.CreateNamedStreamSegment(previous, property);
                return;
            }

            // Handle a strongly-typed property.
            ODataPathSegment segment = null;

            if (property.PropertyKind == EdmPropertyKind.Navigation)
            {
                var navigationProperty = (IEdmNavigationProperty)property;
                IEdmNavigationSource navigationSource = previous.TargetEdmNavigationSource.FindNavigationTarget(navigationProperty);

                segment = new NavigationPropertySegment(navigationProperty, navigationSource);
            }
            else
            {
                segment = new PropertySegment((IEdmStructuralProperty)property);
                switch (property.Type.TypeKind())
                {
                    case EdmTypeKind.Complex:
                        segment.TargetKind = RequestTargetKind.ComplexObject;
                        break;
                    case EdmTypeKind.Collection:
                        segment.TargetKind = RequestTargetKind.Collection;
                        break;
                    case EdmTypeKind.Enum:
                        segment.TargetKind = RequestTargetKind.Enum;
                        break;
                    default:
                        Debug.Assert(property.Type.IsPrimitive() || property.Type.IsTypeDefinition(), "must be primitive type or type definition property");
                        segment.TargetKind = RequestTargetKind.Primitive;
                        break;
                }
            }

            this.parsedSegments.Add(segment);

            if (!(queryPortion == null || property.Type.IsCollection() && property.Type.AsCollection().ElementType().IsEntity()))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            this.TryBindKeyFromParentheses(queryPortion);
        }
        private ODataPayloadKind ParseContextUriFragment(string fragment, Func <IEdmType, string, IEdmType> clientCustomTypeResolver, bool throwIfMetadataConflict, out bool isUndeclared)
        {
            bool           hasItemSelector = false;
            ODataDeltaKind kind            = ODataDeltaKind.None;

            isUndeclared = false;

            // Deal with /$entity
            if (fragment.EndsWith(ODataConstants.ContextUriFragmentItemSelector, StringComparison.Ordinal))
            {
                hasItemSelector = true;
                fragment        = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriFragmentItemSelector.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeltaResourceSet, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.ResourceSet;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeltaResourceSet.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeletedEntry, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.DeletedEntry;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeletedEntry.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeltaLink, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.Link;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeltaLink.Length);
            }
            else if (fragment.EndsWith(ODataConstants.ContextUriDeletedLink, StringComparison.Ordinal))
            {
                kind     = ODataDeltaKind.DeletedLink;
                fragment = fragment.Substring(0, fragment.Length - ODataConstants.ContextUriDeletedLink.Length);
            }

            this.parseResult.DeltaKind = kind;

            // Deal with query option
            if (fragment.EndsWith(")", StringComparison.Ordinal))
            {
                int index = fragment.Length - 2;
                for (int rcount = 1; rcount > 0 && index > 0; --index)
                {
                    switch (fragment[index])
                    {
                    case '(':
                        rcount--;
                        break;

                    case ')':
                        rcount++;
                        break;
                    }
                }

                if (index == 0)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                string previous = fragment.Substring(0, index + 1);

                // Don't treat Collection(Edm.Type) as SelectExpand segment
                if (!previous.Equals("Collection", StringComparison.Ordinal))
                {
                    string selectExpandStr = fragment.Substring(index + 2);
                    selectExpandStr = selectExpandStr.Substring(0, selectExpandStr.Length - 1);

                    // Do not treat Key as SelectExpand segment
                    if (KeyPattern.IsMatch(selectExpandStr))
                    {
                        throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_LastSegmentIsKeySegment(UriUtils.UriToString(this.parseResult.ContextUri)));
                    }

                    this.parseResult.SelectQueryOption = ExtractSelectQueryOption(selectExpandStr);
                    fragment = previous;
                }
            }

            ODataPayloadKind detectedPayloadKind = ODataPayloadKind.Unsupported;
            EdmTypeResolver  edmTypeResolver     = new EdmTypeReaderResolver(this.model, clientCustomTypeResolver);

            if (!fragment.Contains(ODataConstants.UriSegmentSeparator) && !hasItemSelector && kind == ODataDeltaKind.None)
            {
                // Service document: no fragment
                if (fragment.Length == 0)
                {
                    detectedPayloadKind = ODataPayloadKind.ServiceDocument;
                }
                else if (fragment.Equals(ODataConstants.CollectionPrefix + "(" + ODataConstants.EntityReferenceSegmentName + ")", StringComparison.Ordinal))
                {
                    detectedPayloadKind = ODataPayloadKind.EntityReferenceLinks;
                }
                else if (fragment.Equals(ODataConstants.EntityReferenceSegmentName, StringComparison.Ordinal))
                {
                    detectedPayloadKind = ODataPayloadKind.EntityReferenceLink;
                }
                else
                {
                    var foundNavigationSource = this.model.FindDeclaredNavigationSource(fragment);

                    if (foundNavigationSource != null)
                    {
                        // Resource Set: {schema.entity-container.entity-set} or Singleton: {schema.entity-container.singleton}
                        this.parseResult.NavigationSource = foundNavigationSource;
                        this.parseResult.EdmType          = edmTypeResolver.GetElementType(foundNavigationSource);
                        detectedPayloadKind = foundNavigationSource is IEdmSingleton ? ODataPayloadKind.Resource : ODataPayloadKind.ResourceSet;
                    }
                    else
                    {
                        // Property: {schema.type} or Collection({schema.type}) where schema.type is primitive or complex.
                        detectedPayloadKind = this.ResolveType(fragment, clientCustomTypeResolver, throwIfMetadataConflict);
                        Debug.Assert(
                            this.parseResult.EdmType.TypeKind == EdmTypeKind.Primitive || this.parseResult.EdmType.TypeKind == EdmTypeKind.Enum || this.parseResult.EdmType.TypeKind == EdmTypeKind.TypeDefinition || this.parseResult.EdmType.TypeKind == EdmTypeKind.Complex || this.parseResult.EdmType.TypeKind == EdmTypeKind.Collection || this.parseResult.EdmType.TypeKind == EdmTypeKind.Entity || this.parseResult.EdmType.TypeKind == EdmTypeKind.Untyped,
                            "The first context URI segment must be a set or a non-entity type.");
                    }
                }
            }
            else
            {
                Debug.Assert(this.parseResult.MetadataDocumentUri.IsAbsoluteUri, "this.parseResult.MetadataDocumentUri.IsAbsoluteUri");

                string metadataDocumentStr = UriUtils.UriToString(this.parseResult.MetadataDocumentUri);

                if (!metadataDocumentStr.EndsWith(ODataConstants.UriMetadataSegment, StringComparison.Ordinal))
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                Uri serviceRoot = new Uri(metadataDocumentStr.Substring(0, metadataDocumentStr.Length - ODataConstants.UriMetadataSegment.Length));

                ODataUriParser odataUriParser = new ODataUriParser(this.model, serviceRoot, new Uri(serviceRoot, fragment));

                ODataPath path;
                try
                {
                    path = odataUriParser.ParsePath();
                }
                catch (ODataException)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                if (path.Count == 0)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }

                this.parseResult.Path = path;

                parseResult.NavigationSource = path.NavigationSource();
                parseResult.EdmType          = path.LastSegment.EdmType;

                ODataPathSegment lastSegment = path.TrimEndingTypeSegment().LastSegment;
                if (lastSegment is EntitySetSegment || lastSegment is NavigationPropertySegment)
                {
                    if (kind != ODataDeltaKind.None)
                    {
                        detectedPayloadKind = ODataPayloadKind.Delta;
                    }
                    else
                    {
                        detectedPayloadKind = hasItemSelector ? ODataPayloadKind.Resource : ODataPayloadKind.ResourceSet;
                    }

                    if (this.parseResult.EdmType is IEdmCollectionType)
                    {
                        var collectionTypeReference = this.parseResult.EdmType.ToTypeReference().AsCollection();
                        if (collectionTypeReference != null)
                        {
                            this.parseResult.EdmType = collectionTypeReference.ElementType().Definition;
                        }
                    }
                }
                else if (lastSegment is SingletonSegment)
                {
                    detectedPayloadKind = ODataPayloadKind.Resource;
                }
                else if (path.IsIndividualProperty())
                {
                    isUndeclared        = path.IsUndeclared();
                    detectedPayloadKind = ODataPayloadKind.Property;
                    IEdmComplexType complexType = parseResult.EdmType as IEdmComplexType;
                    if (complexType != null)
                    {
                        detectedPayloadKind = ODataPayloadKind.Resource;
                    }
                    else
                    {
                        IEdmCollectionType collectionType = parseResult.EdmType as IEdmCollectionType;

                        if (collectionType != null)
                        {
                            if (collectionType.ElementType.IsComplex())
                            {
                                this.parseResult.EdmType = collectionType.ElementType.Definition;
                                detectedPayloadKind      = ODataPayloadKind.ResourceSet;
                            }
                            else
                            {
                                detectedPayloadKind = ODataPayloadKind.Collection;
                            }
                        }
                    }
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightContextUriParser_InvalidContextUrl(UriUtils.UriToString(this.parseResult.ContextUri)));
                }
            }

            return(detectedPayloadKind);
        }
Пример #29
0
        /// <summary>
        /// Creates a named stream segment
        /// </summary>
        /// <param name="previous">previous segment info.</param>
        /// <param name="streamProperty">stream property to create the segment for.</param>
        private void CreateNamedStreamSegment(ODataPathSegment previous, IEdmProperty streamProperty)
        {
            Debug.Assert(streamProperty.Type.IsStream(), "streamProperty.Type.IsStream()");

            // Handle Named Stream.
            ODataPathSegment segment = new PropertySegment((IEdmStructuralProperty)streamProperty);
            segment.TargetKind = RequestTargetKind.MediaResource;
            segment.SingleResult = true;
            segment.TargetEdmType = previous.TargetEdmType;
            Debug.Assert(segment.Identifier != UriQueryConstants.ValueSegment, "'$value' cannot be the name of a named stream.");

            this.parsedSegments.Add(segment);
        }
Пример #30
0
 /// <summary>
 /// Initializes a new instance of the <see cref="LinksPathSegment" /> class.
 /// </summary>
 /// <param name="previous">The previous segment in the path.</param>
 public LinksPathSegment(ODataPathSegment previous)
     : base(previous)
 {
     EdmType   = previous.EdmType;
     EntitySet = previous.EntitySet;
 }
Пример #31
0
        public void UnqualifiedActionNameOnOpenTypeShouldBeInterpretedAsAnOpenProperty()
        {
            ODataPathSegment segment = SelectPathSegmentTokenBinder.ConvertNonTypeTokenToSegment(new NonSystemToken("Restore", null, null), HardCodedTestModel.TestModel, HardCodedTestModel.GetPaintingType());

            segment.ShouldBeOpenPropertySegment("Restore");
        }
        /// <summary>
        /// Java specific function to generate Object constructor section of a code snippet. In the event that another object is needed in the middle of generation,
        /// a recursive call is made to sort out the needed object.
        /// </summary>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="jsonString">Json string from which the information of the object to be initialized is held</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        /// <param name="usedVarNames">List to keep track of variable names used to prevent use of the same variable name</param>
        private static string JavaGenerateObjectFromJson(ODataPathSegment pathSegment, string jsonString, List <string> path, List <string> usedVarNames = null)
        {
            var stringBuilder = new StringBuilder();
            var jsonObject    = JsonConvert.DeserializeObject(jsonString);

            usedVarNames = usedVarNames ?? new List <string>();//make sure list is not null

            switch (jsonObject)
            {
            case string _:
            {
                var enumString = GenerateEnumString(jsonObject.ToString(), pathSegment, path);
                if (!string.IsNullOrEmpty(enumString))
                {
                    //Enum is accessed as the Classname then enum type e.g Importance.LOW
                    stringBuilder.Append($"{enumString.Split(".").First()} {path.Last()} = {enumString};\r\n");
                }
                else if (jsonObject.Equals("true") || jsonObject.Equals("false"))
                {
                    stringBuilder.Append($"boolean {path.Last()} = {jsonObject};\r\n");        //boolean primitives values masquerading as strings.
                }
                else
                {
                    stringBuilder.Append($"String {path.Last()} = \"{jsonObject}\";\r\n");
                }
            }
            break;

            case JObject jObject:
            {
                var currentVarName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                var className      = GetJavaClassNameFromOdataPath(pathSegment, path);
                stringBuilder.Append($"{className} { currentVarName } = new {className}();\r\n");
                //initialize each member/property of the object
                foreach (var(key, jToken) in jObject)
                {
                    var value   = JsonConvert.SerializeObject(jToken);
                    var newPath = path.Append(key).ToList();           //add new identifier to the path

                    if (key.Contains("@odata") || key.StartsWith("@")) //sometimes @odata maybe in the middle e.g."*****@*****.**"
                    {
                        stringBuilder = GenerateJavaAdditionalDataSection(stringBuilder, key, jToken.ToString(), className, currentVarName);
                        continue;
                    }
                    switch (jToken.Type)
                    {
                    case JTokenType.Array:
                    case JTokenType.Object:
                        //new nested object needs to be constructed so call this function recursively to make it
                        stringBuilder.Append($"{JavaGenerateObjectFromJson(pathSegment, value, newPath, usedVarNames)}");
                        stringBuilder.Append(jToken.Type == JTokenType.Array
                                        ? $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(newPath.Last()+"List", usedVarNames) };\r\n"
                                        : $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(newPath.Last(), usedVarNames) };\r\n");
                        break;

                    case JTokenType.String:
                        var enumString = GenerateEnumString(jToken.ToString(), pathSegment, newPath);
                        //check if the type is an enum and handle it
                        stringBuilder.Append(!string.IsNullOrEmpty(enumString)
                                        ? $"{ currentVarName }.{newPath.Last()} = {enumString};\r\n"
                                        : $"{ currentVarName }.{newPath.Last()} = {value.Replace("\n", "").Replace("\r", "")};\r\n");
                        break;

                    default:
                        stringBuilder.Append($"{ currentVarName }.{newPath.Last()} = { value.Replace("\n", "").Replace("\r", "") };\r\n");
                        break;
                    }
                    usedVarNames.Add(jToken.Type == JTokenType.Array? $"{newPath.Last()}List": newPath.Last());        //add used variable name to used list
                }
            }
            break;

            case JArray array:
            {
                var objectList = array.Children <JObject>();
                if (objectList.Any())
                {
                    var className       = GetJavaClassNameFromOdataPath(pathSegment, path);
                    var currentListName = EnsureJavaVariableNameIsUnique(path.Last() + "List", usedVarNames);
                    //Item is a list/array so declare a typed list
                    stringBuilder.Append($"LinkedList<{className}> {currentListName} = new LinkedList<{className}>();\r\n");
                    foreach (var item in objectList)
                    {
                        var currentListItemName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                        var jsonItemString      = JsonConvert.SerializeObject(item);
                        //we need to create a new object
                        var objectStringFromJson = JavaGenerateObjectFromJson(pathSegment, jsonItemString, path, usedVarNames);
                        stringBuilder.Append($"{objectStringFromJson}");
                        stringBuilder.Append($"{currentListName}.add({currentListItemName});\r\n");
                        usedVarNames.Add(path.Last());        //add used variable name to used list
                    }
                }
                else
                {
                    stringBuilder.Append($"LinkedList<String> {path.Last()}List = new LinkedList<String>();\r\n");
                    //its not nested objects but a string collection
                    foreach (var element in array)
                    {
                        stringBuilder.Append($"{path.Last()}List.add(\"{element.Value<string>()}\");\r\n");
                    }
                }
            }
            break;

            case null:
                //do nothing
                break;

            default:
                var primitive = jsonObject.ToString();
                //json deserializer capitalizes the bool types so undo that
                if (primitive.Equals("True", StringComparison.Ordinal) || primitive.Equals("False", StringComparison.Ordinal))
                {
                    stringBuilder.Append($"boolean {path.Last()} = {CommonGenerator.LowerCaseFirstLetter(primitive)};\r\n");
                }
                else
                {
                    stringBuilder.Append($"int {path.Last()} = {primitive};\r\n");    //item is a primitive print as is
                }
                break;
            }

            //check if this is the outermost object in a potential nested object structure and needs the semicolon termination character.
            return(path.Count == 1 ? $"{stringBuilder.ToString().TrimEnd()}\r\n\r\n" : stringBuilder.ToString());
        }
Пример #33
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ValuePathSegment" /> class.
 /// </summary>
 /// <param name="previous">The previous segment in the path.</param>
 public ValuePathSegment(ODataPathSegment previous)
     : base(previous)
 {
     EdmType = previous.EdmType;
     EntitySet = previous.EntitySet;
 }
Пример #34
0
 /// <summary>
 /// Matches the template with an <see cref="ODataPathSegment"/>.
 /// </summary>
 /// <param name="pathSegment">The path segment to match this template with.</param>
 /// <param name="values">The dictionary of matches to be updated if the segment matches the template.</param>
 /// <returns><c>true</c> if the segment matches the template; otherwise, <c>false</c>.</returns>
 public virtual bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values)
 {
     return(false);
 }
        /// <summary>Creates the first <see cref="SegmentInfo"/> for a request.</summary>
        /// <param name="segment">The text of the segment.</param>
        /// <returns>A description of the information on the segment.</returns>
        private SegmentInfo CreateFirstSegment(ODataPathSegment segment)
        {
            Debug.Assert(segment != null, "identifier != null");

            // Look for well-known system entry points.
            if (segment is MetadataSegment)
            {
                return new SegmentInfo { Identifier = XmlConstants.UriMetadataSegment, TargetKind = RequestTargetKind.Metadata };
            }

            if (segment is BatchSegment)
            {
                return new SegmentInfo { Identifier = XmlConstants.UriBatchSegment, TargetKind = RequestTargetKind.Batch };
            }

            if (segment is CountSegment)
            {
                // $count on root: throw
                throw DataServiceException.CreateResourceNotFound(Strings.RequestUriProcessor_CountOnRoot);
            }

            // Look for a service operation.
            OperationImportSegment serviceOperation = segment as OperationImportSegment;
            if (serviceOperation != null)
            {
                Debug.Assert(serviceOperation.OperationImports.Count() == 1, "Operation import segment should only ever have exactly one operation. Was a change made to how MetadataProviderEdmModel finds actions/service operations");
                var operationImport = serviceOperation.OperationImports.Single();
                var operation = ((MetadataProviderEdmOperationImport)operationImport).ServiceOperation;
                Debug.Assert(operation != null, "operation != null");

                if (operation.Kind == OperationKind.ServiceOperation)
                {
                    return CreateSegmentForServiceOperation(operation);
                }

                Debug.Assert(operation.Kind == OperationKind.Action, "serviceAction.Kind == OperationKind.Action");
                return this.CreateSegmentForServiceAction(null /*previousSegment*/, operation);
            }

            var batchReferenceSegment = segment as BatchReferenceSegment;
            if (batchReferenceSegment != null)
            {
                SegmentInfo referencedSegmentInfo = this.crossReferenceCallback(batchReferenceSegment.ContentId);
                Debug.Assert(referencedSegmentInfo != null, "Could not find SegmentInfo for content-id: " + batchReferenceSegment.ContentId);
                referencedSegmentInfo.Identifier = batchReferenceSegment.ContentId;
                return referencedSegmentInfo;
            }

            // Look for an entity set.
            EntitySetSegment entitySetSegment = segment as EntitySetSegment;
            if (entitySetSegment != null)
            {
                var container = ((IResourceSetBasedEdmEntitySet)entitySetSegment.EntitySet).ResourceSet;
                Debug.Assert(container != null, "container != null");
                SegmentInfo segmentInfo = new SegmentInfo
                {
                    Identifier = container.Name,
                    TargetResourceSet = container,
                    TargetResourceType = container.ResourceType,
                    TargetSource = RequestTargetSource.EntitySet,
                    TargetKind = RequestTargetKind.Resource,
                    SingleResult = false
                };

                return segmentInfo;
            }

            WebUtil.CheckResourceExists(false, segment.ToString());
            return null;
        }
        internal static bool TryBindAsOperation(PathSegmentToken pathToken, IEdmModel model, IEdmStructuredType entityType, out ODataPathSegment segment)
        {
            Debug.Assert(pathToken != null, "pathToken != null");
            Debug.Assert(entityType != null, "bindingType != null");

            List <IEdmOperation> possibleFunctions = new List <IEdmOperation>();

            // Catch all catchable exceptions as FindDeclaredBoundOperations is implemented by anyone.
            // If an exception occurs it will be supressed and the possible functions will be empty and return false.
            try
            {
                int wildCardPos = pathToken.Identifier.IndexOf("*", StringComparison.Ordinal);
                if (wildCardPos > -1)
                {
                    string namespaceName = pathToken.Identifier.Substring(0, wildCardPos - 1);
                    possibleFunctions = model.FindBoundOperations(entityType).Where(o => o.Namespace == namespaceName).ToList();
                }
                else
                {
                    NonSystemToken nonSystemToken = pathToken as NonSystemToken;
                    IList <string> parameterNames = new List <string>();
                    if (nonSystemToken != null && nonSystemToken.NamedValues != null)
                    {
                        parameterNames = nonSystemToken.NamedValues.Select(s => s.Name).ToList();
                    }

                    if (parameterNames.Count > 0)
                    {
                        // Always force to use fully qualified name when select operation
                        possibleFunctions = model.FindBoundOperations(entityType).FilterByName(true, pathToken.Identifier).FilterOperationsByParameterNames(parameterNames, false).ToList();
                    }
                    else
                    {
                        possibleFunctions = model.FindBoundOperations(entityType).FilterByName(true, pathToken.Identifier).ToList();
                    }
                }
            }
            catch (Exception exc)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(exc))
                {
                    throw;
                }
            }

            possibleFunctions = possibleFunctions.EnsureOperationsBoundWithBindingParameter().ToList();

            // Only filter if there is more than one and its needed.
            if (possibleFunctions.Count > 1)
            {
                possibleFunctions = possibleFunctions.FilterBoundOperationsWithSameTypeHierarchyToTypeClosestToBindingType(entityType).ToList();
            }

            if (possibleFunctions.Count <= 0)
            {
                segment = null;
                return(false);
            }

            segment = new OperationSegment(possibleFunctions, null /*entitySet*/);
            return(true);
        }
        /// <summary>
        /// Tries to create a type name segment if the given identifier refers to a known type.
        /// </summary>
        /// <param name="previous">previous segment info.</param>
        /// <param name="segment">The segment being interpreted.</param>
        /// <param name="typeNameSegment">The type name segment, if one was created.</param>
        /// <returns>Whether or not a type segment was created for the identifier.</returns>
        private bool TryCreateTypeNameSegment(SegmentInfo previous, ODataPathSegment segment, out SegmentInfo typeNameSegment)
        {
            var typeSegment = segment as TypeSegment;
            if (typeSegment == null || previous.TargetResourceSet == null)
            {
                typeNameSegment = null;
                return false;
            }

            ResourceType targetResourceType = MetadataProviderUtils.GetResourceType(typeSegment);
            
            // if the new type segment prevents any results from possibly being returned, then short-circuit and throw a 404.
            ResourceType previousResourceType = previous.TargetResourceType;
            Debug.Assert(previousResourceType != null, "previous.TargetResourceType != null");
            if (!targetResourceType.IsAssignableFrom(previousResourceType) && !previousResourceType.IsAssignableFrom(targetResourceType))
            {
                throw DataServiceException.CreateBadRequestError(Strings.RequestUriProcessor_InvalidTypeIdentifier_UnrelatedType(targetResourceType.FullName, previousResourceType.FullName));
            }

            // Since we allow derived navigation properties or named streams in V1/V2, the server will generate edit links and navigation links with type segment in it.
            // Hence we need to be able to process type segment in the request even when the server MPV is set to V1/V2. But we do not want to expose new functionality
            // like filtering collections based on type, etc on V1/V2 servers. Hence only checking for MPV to be v3 or greater if the previous segment is a collection
            if (!previous.SingleResult)
            {
                VersionUtil.CheckMaxProtocolVersion(VersionUtil.Version4Dot0, this.maxProtocolVersion);
            }

            typeNameSegment = new SegmentInfo
            {
                Identifier = targetResourceType.FullName,
                Operation = previous.Operation,
                TargetKind = previous.TargetKind,
                TargetSource = previous.TargetSource,
                TargetResourceType = targetResourceType,
                SingleResult = previous.SingleResult,
                TargetResourceSet = previous.TargetResourceSet,
                ProjectedProperty = previous.ProjectedProperty,
                Key = previous.Key,
                RequestExpression = previous.RequestExpression,
                RequestEnumerable = previous.RequestEnumerable,
                IsTypeIdentifierSegment = true
            };

            return true;
        }
        private static bool TryBindAsDeclaredProperty(PathSegmentToken tokenIn, IEdmStructuredType edmType, ODataUriResolver resolver, out ODataPathSegment segment)
        {
            IEdmProperty prop = resolver.ResolveProperty(edmType, tokenIn.Identifier);

            if (prop == null)
            {
                segment = null;
                return(false);
            }

            if (prop.PropertyKind == EdmPropertyKind.Structural)
            {
                segment = new PropertySegment((IEdmStructuralProperty)prop);
                return(true);
            }

            if (prop.PropertyKind == EdmPropertyKind.Navigation)
            {
                segment = new NavigationPropertySegment((IEdmNavigationProperty)prop, null /*TODO set*/);
                return(true);
            }

            throw new ODataException(ODataErrorStrings.SelectExpandBinder_UnknownPropertyType(prop.Name));
        }
Пример #39
0
 private void HandleSingletonPathSegment(ODataPathSegment segment)
 {
     var singletonPathSegment = (SingletonSegment)segment;
     var singleton = singletonPathSegment.Singleton;
     this.queryable = this.api.GetQueryableSource(singleton.Name, (object[])null);
     this.currentType = this.queryable.ElementType;
 }
        /// <summary>
        /// Java specific function to generate Object constructor section of a code snippet. In the event that another object is needed in the middle of generation,
        /// a recursive call is made to sort out the needed object.
        /// </summary>
        /// <param name="pathSegment">Odata Function/Entity from which the object is needed</param>
        /// <param name="jsonString">Json string from which the information of the object to be initialized is held</param>
        /// <param name="path">List of strings/identifier showing the path through the Edm/json structure to reach the Class Identifier from the segment</param>
        /// <param name="usedVarNames">List to keep track of variable names used to prevent use of the same variable name</param>
        private string JavaGenerateObjectFromJson(ODataPathSegment pathSegment, string jsonString, List <string> path, List <string> usedVarNames = null)
        {
            var stringBuilder = new StringBuilder();
            var jsonObject    = JsonConvert.DeserializeObject(jsonString);

            usedVarNames = usedVarNames ?? new List <string>();//make sure list is not null
            var className = GetJavaReturnTypeName(pathSegment, path);

            switch (jsonObject)
            {
            case string _:
            {
                var enumIsFlags    = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path) is IEdmEnumType enumType && enumType.IsFlags;
                var enumString     = GenerateEnumString(jsonObject.ToString(), pathSegment, path);
                var currentVarName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                if (className == "String")
                {
                    stringBuilder.Append($"String {currentVarName} = \"{jsonObject}\";\r\n");
                }
                else if (!string.IsNullOrEmpty(enumString))
                {
                    //Enum is accessed as the Classname then enum type e.g Importance.LOW
                    var enumTypeName = enumString.Split(".").First();
                    if (enumIsFlags)
                    {
                        stringBuilder.Append($"EnumSet<{enumTypeName}> {currentVarName} = EnumSet.of({enumString});\r\n");
                    }
                    else
                    {
                        stringBuilder.Append($"{enumTypeName} {currentVarName} = {enumString.Split(",", StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()};\r\n");
                    }
                }
                else if (jsonObject.Equals("true") || jsonObject.Equals("false"))
                {
                    stringBuilder.Append($"boolean {currentVarName} = {jsonObject};\r\n");        //boolean primitives values masquerading as strings.
                }
                else
                {
                    stringBuilder.Append($"{GetJavaReturnTypeName(pathSegment, path)} {currentVarName} = {GenerateSpecialClassString($"{jsonObject}", pathSegment, path)};\r\n");
                }
            }
            break;

            case JObject jObject:
            {
                var currentVarName         = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                var localClassNameOverride = className.Equals("JsonElement") ? "JsonObject" : className;         //jsonelements are abstract and cannot be instanciated
                stringBuilder.Append($"{className} { currentVarName } = new {localClassNameOverride}();\r\n");
                //initialize each member/property of the object
                foreach (var(key, jToken) in jObject)
                {
                    var value   = JsonConvert.SerializeObject(jToken);
                    var newPath = path.Append(key).ToList();           //add new identifier to the path

                    if (key.Contains("@odata") || key.StartsWith("@")) //sometimes @odata maybe in the middle e.g."*****@*****.**"
                    {
                        stringBuilder = GenerateJavaAdditionalDataSection(stringBuilder, key, jToken.ToString(), className, currentVarName);
                        continue;
                    }
                    switch (jToken.Type)
                    {
                    case JTokenType.Array:
                    case JTokenType.Object:
                        // in the case we have a collection page property, we need to reference the collection page variable instead
                        var collectionType  = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, newPath);
                        var referenceSuffix = collectionType.TypeKind == EdmTypeKind.Entity ? $"Collection{page}" : "List";
                        var variableName    = (referenceSuffix.Contains(page) ? collectionType.FullTypeName().Split('.').Last() : newPath.Last()) + referenceSuffix;
                        //new nested object needs to be constructed so call this function recursively to make it
                        stringBuilder.Append($"{JavaGenerateObjectFromJson(pathSegment, value, newPath, usedVarNames)}");
                        stringBuilder.Append(jToken.Type == JTokenType.Array
                                        ? $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(variableName, usedVarNames) };\r\n"
                                        : $"{ currentVarName }.{ newPath.Last() } = { EnsureJavaVariableNameIsUnique(newPath.Last(), usedVarNames) };\r\n");
                        break;

                    case JTokenType.String:
                        var enumString  = GenerateEnumString(jToken.ToString(), pathSegment, newPath);
                        var enumIsFlags = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, newPath) is IEdmEnumType enumType && enumType.IsFlags;
                        stringBuilder.Append($"{ currentVarName }.{newPath.Last()} = ");
                        if (string.IsNullOrEmpty(enumString))
                        {
                            stringBuilder.Append($"{GenerateSpecialClassString($"{value}", pathSegment, newPath)};\r\n");
                        }
                        else if (enumIsFlags)
                        {
                            stringBuilder.Append($"EnumSet.of({enumString});\r\n");
                        }
                        else
                        {
                            stringBuilder.Append($"{enumString.Split(",", StringSplitOptions.RemoveEmptyEntries).FirstOrDefault()};\r\n");
                        }
                        break;

                    default:
                        stringBuilder.Append($"{ currentVarName }.{newPath.Last()} = { GenerateSpecialClassString($"{value}", pathSegment, newPath)};\r\n");
                        break;
                    }
                    usedVarNames.Add(jToken.Type == JTokenType.Array ? $"{newPath.Last()}List" : newPath.Last());        //add used variable name to used list
                }
            }
            break;

            case JArray array:
            {
                var objectList      = array.Children <JObject>();
                var currentListName = EnsureJavaVariableNameIsUnique(path.Last() + "List", usedVarNames);
                var collectionType  = CommonGenerator.GetEdmTypeFromIdentifier(pathSegment, path);
                if (objectList.Any())
                {
                    //Item is a list/array so declare a typed list
                    stringBuilder.Append($"LinkedList<{className}> {currentListName} = new LinkedList<{className}>();\r\n");
                    foreach (var item in objectList)
                    {
                        var currentListItemName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                        var jsonItemString      = JsonConvert.SerializeObject(item);
                        //we need to create a new object
                        var objectStringFromJson = JavaGenerateObjectFromJson(pathSegment, jsonItemString, path, usedVarNames);
                        stringBuilder.Append($"{objectStringFromJson}");
                        stringBuilder.Append($"{currentListName}.add({currentListItemName});\r\n");
                        usedVarNames.Add(path.Last());        //add used variable name to used list
                    }
                    if (collectionType.TypeKind == EdmTypeKind.Entity)
                    {
                        var currentPageTypeName           = CommonGenerator.UppercaseFirstLetter($"{CommonGenerator.UppercaseFirstLetter(collectionType.FullTypeName().Split('.').Last())}Collection{page}");
                        var currentPageCollectionName     = EnsureJavaVariableNameIsUnique(CommonGenerator.LowerCaseFirstLetter(currentPageTypeName), usedVarNames);
                        var currentResponseTypeName       = currentPageTypeName.Replace(page, "Response");
                        var currentResponseCollectionName = EnsureJavaVariableNameIsUnique(CommonGenerator.LowerCaseFirstLetter(currentResponseTypeName), usedVarNames);
                        stringBuilder.Append($"{currentResponseTypeName} {currentResponseCollectionName} = new {currentResponseTypeName}();\r\n");
                        stringBuilder.Append($"{currentResponseCollectionName}.value = {currentListName};\r\n");
                        stringBuilder.Append($"{currentPageTypeName} {currentPageCollectionName} = new {currentPageTypeName}({currentResponseCollectionName}, null);\r\n");
                    }
                }
                else if (collectionType.TypeKind == EdmTypeKind.Enum)
                {
                    stringBuilder.Append($"LinkedList<{className}> {currentListName} = new LinkedList<{className}>();\r\n");
                    array?.Select(x => x.Value <string>())?.
                    SelectMany(x => GenerateEnumString(x, pathSegment, path)?.
                               Split(",", StringSplitOptions.RemoveEmptyEntries))?.
                    ToList()?.
                    ForEach(x => stringBuilder.Append($"{currentListName}.add({x});\r\n"));
                }
                else
                {
                    stringBuilder.Append($"LinkedList<{className}> {currentListName} = new LinkedList<{className}>();\r\n");
                    //its not nested objects but a string collection
                    foreach (var element in array)
                    {
                        stringBuilder.Append($"{currentListName}.add({(className == "String" ? AddQuotesIfMising(element.Value<string>()) : GenerateSpecialClassString(element.Value<string>(), pathSegment, path))});\r\n");
                    }
                }
            }
            break;

            case null:
                //do nothing
                break;

            default:
                var primitive  = jsonObject.ToString();
                var curVarName = EnsureJavaVariableNameIsUnique(path.Last(), usedVarNames);
                stringBuilder.Append($"{className} {curVarName} = {(className == "String" ? AddQuotesIfMising(primitive) : GenerateSpecialClassString(primitive, pathSegment, path))};\r\n");    //item is a primitive print as is
                break;
            }

            //check if this is the outermost object in a potential nested object structure and needs the semicolon termination character.
            return(path.Count == 1 ? $"{stringBuilder.ToString().TrimEnd()}\r\n\r\n" : stringBuilder.ToString());
        }
Пример #41
0
 private void HandleCountPathSegment(ODataPathSegment segment)
 {
     this.IsCountPathSegmentPresent = true;
 }
Пример #42
0
 /// <summary>
 /// Handle validating a ODataPathSegment
 /// </summary>
 /// <param name="segment">The path segment to valdiate.</param>
 public override void Handle(ODataPathSegment segment)
 {
     ValidateItemAndType(segment);
 }
Пример #43
0
        private void HandleKeyValuePathSegment(ODataPathSegment segment)
        {
            var keySegment = (KeySegment)segment;

            var parameterExpression = Expression.Parameter(this.currentType, DefaultNameOfParameterExpression);
            var keyValues = GetPathKeyValues(keySegment);

            BinaryExpression keyFilter = null;
            foreach (KeyValuePair<string, object> keyValuePair in keyValues)
            {
                var equalsExpression =
                    CreateEqualsExpression(parameterExpression, keyValuePair.Key, keyValuePair.Value);
                keyFilter = keyFilter == null ? equalsExpression : Expression.And(keyFilter, equalsExpression);
            }

            var whereExpression = Expression.Lambda(keyFilter, parameterExpression);
            this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType);
        }
Пример #44
0
 /// <summary>
 /// Entry point for validating an <see cref="ODataPathSegment"/>.
 /// </summary>
 /// <param name="segment">The odata path segment to validate</param>
 public void ValidatePath(ODataPathSegment segment)
 {
     segment.HandleWith(this);
 }
Пример #45
0
        private void HandlePropertyAccessPathSegment(ODataPathSegment segment)
        {
            var propertySegment = (PropertySegment)segment;
            var entityParameterExpression = Expression.Parameter(this.currentType);
            var structuralPropertyExpression =
                Expression.Property(entityParameterExpression, propertySegment.Property.Name);

            // Check whether property is null or not before further selection
            if (propertySegment.Property.Type.IsNullable && !propertySegment.Property.Type.IsPrimitive())
            {
                var whereExpression =
                    CreateNotEqualsNullExpression(structuralPropertyExpression, entityParameterExpression);
                this.queryable = ExpressionHelpers.Where(this.queryable, whereExpression, this.currentType);
            }

            if (propertySegment.Property.Type.IsCollection())
            {
                // Produces new query like 'queryable.SelectMany(param => param.PropertyName)'.
                // Suppose 'param.PropertyName' is of type 'IEnumerable<T>', the type of the
                // resulting query would be 'IEnumerable<T>' too.
                this.currentType = structuralPropertyExpression.Type.GetEnumerableItemType();
                var delegateType = typeof(Func<,>).MakeGenericType(
                    this.queryable.ElementType,
                    typeof(IEnumerable<>).MakeGenericType(this.currentType));
                var selectBody =
                    Expression.Lambda(delegateType, structuralPropertyExpression, entityParameterExpression);
                this.queryable = ExpressionHelpers.SelectMany(this.queryable, selectBody, this.currentType);
            }
            else
            {
                // Produces new query like 'queryable.Select(param => param.PropertyName)'.
                this.currentType = structuralPropertyExpression.Type;
                LambdaExpression selectBody =
                    Expression.Lambda(structuralPropertyExpression, entityParameterExpression);
                this.queryable = ExpressionHelpers.Select(this.queryable, selectBody);
            }
        }
        /// <inheritdoc/>
        public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values)
        {
            EntitySetSegment otherEntitySet = pathSegment as EntitySetSegment;

            return(otherEntitySet != null && otherEntitySet.EntitySet == Segment.EntitySet);
        }
        internal static bool TryBindAsOperation(PathSegmentToken pathToken, IEdmModel model, IEdmStructuredType entityType, out ODataPathSegment segment)
        {
            Debug.Assert(pathToken != null, "pathToken != null");
            Debug.Assert(entityType != null, "bindingType != null");

            List<IEdmOperation> possibleFunctions = new List<IEdmOperation>();

            // Catch all catchable exceptions as FindDeclaredBoundOperations is implemented by anyone.
            // If an exception occurs it will be supressed and the possible functions will be empty and return false.
            try
            {
                int wildCardPos = pathToken.Identifier.IndexOf("*", StringComparison.Ordinal);
                if (wildCardPos > -1)
                {
                    string namespaceName = pathToken.Identifier.Substring(0, wildCardPos - 1);
                    possibleFunctions = model.FindBoundOperations(entityType).Where(o => o.Namespace == namespaceName).ToList();
                }
                else
                {
                    NonSystemToken nonSystemToken = pathToken as NonSystemToken;
                    IList<string> parameterNames = new List<string>();
                    if (nonSystemToken != null && nonSystemToken.NamedValues != null)
                    {
                        parameterNames = nonSystemToken.NamedValues.Select(s => s.Name).ToList();
                    }

                    if (parameterNames.Count > 0)
                    {
                        // Always force to use fully qualified name when select operation
                        possibleFunctions = model.FindBoundOperations(entityType).FilterByName(true, pathToken.Identifier).FilterOperationsByParameterNames(parameterNames, false).ToList();
                    }
                    else
                    {
                        possibleFunctions = model.FindBoundOperations(entityType).FilterByName(true, pathToken.Identifier).ToList();
                    }
                }
            }
            catch (Exception exc)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(exc))
                {
                    throw;
                }
            }

            possibleFunctions = possibleFunctions.EnsureOperationsBoundWithBindingParameter().ToList();

            // Only filter if there is more than one and its needed.
            if (possibleFunctions.Count > 1)
            {
                possibleFunctions = possibleFunctions.FilterBoundOperationsWithSameTypeHierarchyToTypeClosestToBindingType(entityType).ToList();
            }

            if (possibleFunctions.Count <= 0)
            {
                segment = null;
                return false;
            }

            segment = new OperationSegment(possibleFunctions, null /*entitySet*/);
            return true;
        }
Пример #48
0
 private void HandleCountPathSegment(ODataPathSegment segment)
 {
     this.IsCountPathSegmentPresent = true;
 }
Пример #49
0
        private bool TryCreateTypeNameSegment(ODataPathSegment previous, string identifier, string parenthesisExpression)
        {
            IEdmType targetEdmType;
            if (previous.TargetEdmType == null || (targetEdmType = UriEdmHelpers.FindTypeFromModel(this.configuration.Model, identifier, this.configuration.Resolver)) == null)
            {
                return false;
            }

            // if the new type segment prevents any results from possibly being returned, then short-circuit and throw a 404.
            IEdmType previousEdmType = previous.TargetEdmType;
            Debug.Assert(previousEdmType != null, "previous.TargetEdmType != null");

            if (previousEdmType.TypeKind == EdmTypeKind.Collection)
            {
                previousEdmType = ((IEdmCollectionType)previousEdmType).ElementType.Definition;
            }

            if (!targetEdmType.IsOrInheritsFrom(previousEdmType) && !previousEdmType.IsOrInheritsFrom(targetEdmType))
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.RequestUriProcessor_InvalidTypeIdentifier_UnrelatedType(targetEdmType.ODataFullName(), previousEdmType.ODataFullName()));
            }

            // We want the type of the type segment to be a collection if the previous segment was a collection
            IEdmType actualTypeOfTheTypeSegment = targetEdmType;

            if (previous.EdmType.TypeKind == EdmTypeKind.Collection)
            {
                // creating a new collection type here because the type in the request is just the item type, there is no user-provided collection type.
                var actualEntityTypeOfTheTypeSegment = actualTypeOfTheTypeSegment as IEdmEntityType;
                if (actualEntityTypeOfTheTypeSegment != null)
                {
                    actualTypeOfTheTypeSegment = new EdmCollectionType(new EdmEntityTypeReference(actualEntityTypeOfTheTypeSegment, false));
                }
                else
                {
                    throw new ODataException(Strings.PathParser_TypeCastOnlyAllowedAfterEntityCollection(identifier));
                }
            }

            var typeNameSegment = (ODataPathSegment)new TypeSegment(actualTypeOfTheTypeSegment, previous.TargetEdmNavigationSource)
            {
                Identifier = identifier,
                TargetKind = previous.TargetKind,
                SingleResult = previous.SingleResult,
                TargetEdmType = targetEdmType
            };

            this.parsedSegments.Add(typeNameSegment);

            // Key expressions are allowed on Type segments
            this.TryBindKeyFromParentheses(parenthesisExpression);

            return true;
        }
Пример #50
0
 private void HandleValuePathSegment(ODataPathSegment segment)
 {
     this.IsValuePathSegmentPresent = true;
 }
Пример #51
0
 /// <summary>
 /// Determines the entity set for segment.
 /// </summary>
 /// <param name="identifier">The identifier.</param>
 /// <param name="returnType">Type of the return.</param>
 /// <param name="segment">The segment.</param>
 /// <param name="targetset">The targetset.</param>
 /// <param name="singleOperation">The single operation.</param>
 /// <exception cref="ODataException">Throws and exception if entity set not specified.</exception>
 private static void DetermineEntitySetForSegment(string identifier, IEdmTypeReference returnType, ODataPathSegment segment, IEdmEntitySetBase targetset, IEdmOperation singleOperation)
 {
     if (returnType != null)
     {
         segment.TargetEdmNavigationSource = targetset;
         segment.TargetEdmType = returnType.Definition;
         segment.TargetKind = TargetKindFromType(segment.TargetEdmType);
         segment.SingleResult = !singleOperation.ReturnType.IsCollection();
     }
     else
     {
         segment.TargetEdmNavigationSource = null;
         segment.TargetEdmType = null;
         segment.TargetKind = RequestTargetKind.VoidOperation;
     }
 }
        /// <summary>
        /// Function to find the <see cref="EdmType"/> being used by identifier that is the last item in the path collection. This function gets
        /// the right <see cref="IEdmType"/> that is is to be used for the search based on the segment type>
        /// </summary>
        /// <param name="oDataPathSegment">Odata path segment that is the root of the search </param>
        /// <param name="path">List of string that show the depth of the search into the definition from the odataPath type definition</param>
        /// <returns>pair of Edm type name and whether type is found as navigation property</returns>
        public (IEdmType type, bool isNavigationProperty) GetEdmTypeFromIdentifierAndNavigationProperty(ODataPathSegment oDataPathSegment, ICollection <string> path)
        {
            IEdmType type;
            bool     isNavigationProperty;

            switch (oDataPathSegment)
            {
            case KeySegment _:
            case EntitySetSegment _:
            case NavigationPropertySegment _:
            case NavigationPropertyLinkSegment _:
            case SingletonSegment _:
            case PropertySegment _:
            case ValueSegment _:

                (type, isNavigationProperty) = SearchForEdmType(oDataPathSegment.EdmType, path);

                if (null != type)
                {
                    return(type, isNavigationProperty);
                }

                break;

            case OperationSegment operationSegment:
                foreach (var parameters in operationSegment.Operations.First().Parameters)
                {
                    if (!parameters.Name.Equals(path.FirstOrDefault(), StringComparison.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    (type, isNavigationProperty) = SearchForEdmType(parameters.Type.Definition, path);

                    if (null != type)
                    {
                        return(type, isNavigationProperty);
                    }
                }
                break;
            }

            throw new Exception($"No Class Name Found for Identifier {path.Last()}");
        }
Пример #53
0
        /// <summary>
        /// Creates a new segment for an open property.
        /// </summary>
        /// <param name="previous">previous segment info.</param>
        /// <param name="identifier">name of the segment.</param>
        /// <param name="parenthesisExpression">whether this segment has a query portion or not.</param>
        private void CreateOpenPropertySegment(ODataPathSegment previous, string identifier, string parenthesisExpression)
        {
            ODataPathSegment segment = new OpenPropertySegment(identifier);

            // Handle an open type property. If the current leaf isn't an 
            // object (which implies it's already an open type), then
            // it should be marked as an open type.
            if (previous.TargetEdmType != null && !previous.TargetEdmType.IsOpenType())
            {
                throw ExceptionUtil.CreateResourceNotFoundError(segment.Identifier);
            }

            // Open navigation properties are not supported on OpenTypes.
            if (parenthesisExpression != null)
            {
                throw ExceptionUtil.CreateBadRequestError(ODataErrorStrings.OpenNavigationPropertiesNotSupportedOnOpenTypes(segment.Identifier));
            }

            this.parsedSegments.Add(segment);
        }
Пример #54
0
 private static void ValidatePathSegment(ODataPathSegment segment, ODataUrlValidationContext validationContext)
 {
     validationContext.PathValidator.ValidatePath(segment);
 }
Пример #55
0
 /// <summary>
 /// Tries the bind key segment if no resolved parameters and parathesis value exsts.
 /// </summary>
 /// <param name="parenthesisExpression">The parenthesis expression.</param>
 /// <param name="returnType">Type of the return.</param>
 /// <param name="resolvedParameters">The resolved parameters.</param>
 /// <param name="segment">The segment.</param>
 private void TryBindKeySegmentIfNoResolvedParametersAndParathesisValueExsts(string parenthesisExpression, IEdmTypeReference returnType, ICollection<OperationSegmentParameter> resolvedParameters, ODataPathSegment segment)
 {
     IEdmCollectionTypeReference collectionTypeReference = returnType as IEdmCollectionTypeReference;
     if (collectionTypeReference != null && collectionTypeReference.ElementType().IsEntity() && resolvedParameters == null && parenthesisExpression != null)
     {
         // The parameters in the parathesis is a key segment.
         if (this.TryBindKeyFromParentheses(parenthesisExpression))
         {
             this.ThrowIfMustBeLeafSegment(segment);
         }
     }
 }
 /// <summary>
 /// Function to find the <see cref="EdmType"/> being used by identifier that is the last item in the path collection. This function gets
 /// the right <see cref="IEdmType"/> that is is to be used for the search based on the segment type>
 /// </summary>
 /// <param name="oDataPathSegment">Odata path segment that is the root of the search </param>
 /// <param name="path">List of string that show the depth of the search into the definition from the odataPath type definition</param>
 public IEdmType GetEdmTypeFromIdentifier(ODataPathSegment oDataPathSegment, ICollection <string> path)
 {
     var(edmType, _) = GetEdmTypeFromIdentifierAndNavigationProperty(oDataPathSegment, path);
     return(edmType);
 }
Пример #57
0
        /// <inheritdoc/>
        public override bool TryMatch(ODataPathSegment pathSegment, IDictionary <string, object> values)
        {
            SingletonSegment otherSingleton = pathSegment as SingletonSegment;

            return(otherSingleton != null && otherSingleton.Singleton == Segment.Singleton);
        }
Пример #58
0
        private void BuildSelections(
            SelectExpandClause selectExpandClause,
            HashSet <IEdmStructuralProperty> allStructuralProperties,
            HashSet <IEdmNavigationProperty> allNavigationProperties,
            HashSet <IEdmAction> allActions,
            HashSet <IEdmFunction> allFunctions)
        {
            foreach (SelectItem selectItem in selectExpandClause.SelectedItems)
            {
                if (selectItem is ExpandedNavigationSelectItem)
                {
                    continue;
                }

                PathSelectItem pathSelectItem = selectItem as PathSelectItem;

                if (pathSelectItem != null)
                {
                    ValidatePathIsSupported(pathSelectItem.SelectedPath);
                    ODataPathSegment segment = pathSelectItem.SelectedPath.LastSegment;

                    NavigationPropertySegment navigationPropertySegment = segment as NavigationPropertySegment;
                    if (navigationPropertySegment != null)
                    {
                        IEdmNavigationProperty navigationProperty = navigationPropertySegment.NavigationProperty;
                        if (allNavigationProperties.Contains(navigationProperty))
                        {
                            SelectedNavigationProperties.Add(navigationProperty);
                        }
                        continue;
                    }

                    PropertySegment structuralPropertySegment = segment as PropertySegment;
                    if (structuralPropertySegment != null)
                    {
                        IEdmStructuralProperty structuralProperty = structuralPropertySegment.Property;
                        if (allStructuralProperties.Contains(structuralProperty))
                        {
                            SelectedStructuralProperties.Add(structuralProperty);
                        }
                        continue;
                    }

                    OperationSegment operationSegment = segment as OperationSegment;
                    if (operationSegment != null)
                    {
                        AddOperations(allActions, allFunctions, operationSegment);
                        continue;
                    }
                    throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, segment.GetType().Name));
                }

                WildcardSelectItem wildCardSelectItem = selectItem as WildcardSelectItem;
                if (wildCardSelectItem != null)
                {
                    SelectedStructuralProperties = allStructuralProperties;
                    SelectedNavigationProperties = allNavigationProperties;
                    continue;
                }

                NamespaceQualifiedWildcardSelectItem wildCardActionSelection = selectItem as NamespaceQualifiedWildcardSelectItem;
                if (wildCardActionSelection != null)
                {
                    SelectedActions   = allActions;
                    SelectedFunctions = allFunctions;
                    continue;
                }

                throw new ODataException(Error.Format(SRResources.SelectionTypeNotSupported, selectItem.GetType().Name));
            }
        }
Пример #59
0
        /// <summary>
        /// Parses the key properties based on the segment's target type, then creates a new segment for the key.
        /// </summary>
        /// <param name="segment">The segment to apply the key to.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="key">The key to apply.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>The newly created key segment.</returns>
        private static KeySegment CreateKeySegment(ODataPathSegment segment, KeySegment previousKeySegment, SegmentArgumentParser key, ODataUriResolver resolver)
        {
            Debug.Assert(segment != null, "segment != null");
            Debug.Assert(key != null && !key.IsEmpty, "key != null && !key.IsEmpty");
            Debug.Assert(segment.SingleResult == false, "segment.SingleResult == false");

            IEdmEntityType targetEntityType = null;
            if (!(segment.TargetEdmType != null && segment.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType)))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            Debug.Assert(targetEntityType != null, "targetEntityType != null");

            // Make sure the keys specified in the uri matches with the number of keys in the metadata
            var keyProperties = targetEntityType.Key().ToList();
            if (keyProperties.Count != key.ValueCount)
            {
                NavigationPropertySegment currentNavPropSegment = segment as NavigationPropertySegment;
                if (currentNavPropSegment != null)
                {
                    key = KeyFinder.FindAndUseKeysFromRelatedSegment(key, keyProperties, currentNavPropSegment.NavigationProperty, previousKeySegment);
                }

                // if we still didn't find any keys, then throw an error.
                if (keyProperties.Count != key.ValueCount && resolver.GetType() == typeof(ODataUriResolver))
                {
                    throw ExceptionUtil.CreateBadRequestError(ErrorStrings.BadRequest_KeyCountMismatch(targetEntityType.FullName()));
                }
            }

            if (!key.AreValuesNamed && key.ValueCount > 1 && resolver.GetType() == typeof(ODataUriResolver))
            {
                throw ExceptionUtil.CreateBadRequestError(ErrorStrings.RequestUriProcessor_KeysMustBeNamed);
            }

            IEnumerable<KeyValuePair<string, object>> keyPairs;
            if (!key.TryConvertValues(targetEntityType, out keyPairs, resolver))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            IEdmEntityType entityType;
            bool isEntity = segment.TargetEdmType.IsEntityOrEntityCollectionType(out entityType);
            Debug.Assert(isEntity, "Key target type should be an entity type.");

            var keySegment = new KeySegment(keyPairs, entityType, segment.TargetEdmNavigationSource);
            keySegment.CopyValuesFrom(segment);
            keySegment.SingleResult = true;

            return keySegment;
        }
Пример #60
0
        /// <summary>Tries to create a key segment for the given filter if it is non empty.</summary>
        /// <param name="previous">Segment on which to compose.</param>
        /// <param name="previousKeySegment">The parent node's key segment.</param>
        /// <param name="parenthesisExpression">Parenthesis expression of segment.</param>
        /// <param name="keySegment">The key segment that was created if the key was non-empty.</param>
        /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param>
        /// <param name="resolver">The resolver to use.</param>
        /// <returns>Whether the key was non-empty.</returns>
        internal static bool TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, string parenthesisExpression, out ODataPathSegment keySegment, bool enableUriTemplateParsing = false, ODataUriResolver resolver = null)
        {
            Debug.Assert(parenthesisExpression != null, "parenthesisExpression != null");
            Debug.Assert(previous != null, "segment!= null");

            if (resolver == null)
            {
                resolver = ODataUriResolver.Default;
            }

            if (previous.SingleResult)
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            SegmentArgumentParser key;

            if (!SegmentArgumentParser.TryParseKeysFromUri(parenthesisExpression, out key, enableUriTemplateParsing))
            {
                throw ExceptionUtil.CreateSyntaxError();
            }

            // People/NS.Employees() is OK, just like People() is OK
            if (key.IsEmpty)
            {
                keySegment = null;
                return(false);
            }

            keySegment = CreateKeySegment(previous, previousKeySegment, key, resolver);
            return(true);
        }