/// <summary>
        /// Resolves an entity set with an optional type cast and updates the parse result.
        /// </summary>
        /// <param name="entitySet">The entity set to resolve the type cast against.</param>
        /// <param name="typeCast">The optional type cast.</param>
        /// <param name="readerBehavior">Reader behavior if the caller is a reader, null if no reader behavior is available.</param>
        /// <param name="version">The version of the payload being read.</param>
        /// <param name="entitySetElementType">The type of the given entity set.</param>
        /// <returns>The resolved entity type.</returns>
        private IEdmEntityType ResolveTypeCast(IEdmEntitySet entitySet, string typeCast, ODataReaderBehavior readerBehavior, ODataVersion version, IEdmEntityType entitySetElementType)
        {
            Debug.Assert(entitySet != null, "entitySet != null");

            IEdmEntityType entityType = entitySetElementType;

            // Parse the type cast if it exists
            if (!string.IsNullOrEmpty(typeCast))
            {
                EdmTypeKind typeKind;
                entityType = MetadataUtils.ResolveTypeNameForRead(this.model, /*expectedType*/ null, typeCast, readerBehavior, version, out typeKind) as IEdmEntityType;
                if (entityType == null)
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntityTypeInTypeCast(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), typeCast));
                }

                // Validate that the entity type is assignable to the base type of the set
                if (!entitySetElementType.IsAssignableFrom(entityType))
                {
                    throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_IncompatibleEntityTypeInTypeCast(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), typeCast, entitySetElementType.FullName(), entitySet.FullName()));
                }
            }

            return(entityType);
        }
Exemplo n.º 2
0
 /// <summary>
 /// Verifies that CreateParameterReader can be called.
 /// </summary>
 /// <param name="functionImport">The function import whose parameters are being read.</param>
 private static void VerifyCanCreateParameterReader(IEdmFunctionImport functionImport)
 {
     if (functionImport == null)
     {
         throw new ArgumentNullException("functionImport", ODataErrorStrings.ODataJsonInputContext_FunctionImportCannotBeNullForCreateParameterReader("functionImport"));
     }
 }
        /// <summary>
        /// Implementation of the collection reader logic when in state 'Start'.
        /// </summary>
        /// <returns>true if more items can be read from the reader; otherwise false.</returns>
        /// <remarks>
        /// Pre-Condition:  JsonNodeType.None:      assumes that the JSON reader has not been used yet when not reading a nested payload.
        /// Post-Condition: The reader is positioned on the first node of the first item or the EndArray node of an empty item array
        /// </remarks>
        protected override bool ReadAtStartImplementation()
        {
            Debug.Assert(this.State == ODataCollectionReaderState.Start, "this.State == ODataCollectionReaderState.Start");
            Debug.Assert(this.IsReadingNestedPayload || this.verboseJsonCollectionDeserializer.JsonReader.NodeType == JsonNodeType.None, "Pre-Condition: expected JsonNodeType.None when not reading a nested payload.");

            // read the data wrapper depending on whether we are reading a request or response
            this.verboseJsonCollectionDeserializer.ReadPayloadStart(this.IsReadingNestedPayload);

            if (this.IsResultsWrapperExpected && this.verboseJsonCollectionDeserializer.JsonReader.NodeType != JsonNodeType.StartObject)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonCollectionReader_CannotReadWrappedCollectionStart(this.verboseJsonCollectionDeserializer.JsonReader.NodeType));
            }

            if (!this.IsResultsWrapperExpected && this.verboseJsonCollectionDeserializer.JsonReader.NodeType != JsonNodeType.StartArray)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonCollectionReader_CannotReadCollectionStart(this.verboseJsonCollectionDeserializer.JsonReader.NodeType));
            }

            // read the start of the collection until we find the content array
            ODataCollectionStart collectionStart = this.verboseJsonCollectionDeserializer.ReadCollectionStart(this.IsResultsWrapperExpected);

            this.verboseJsonCollectionDeserializer.JsonReader.ReadStartArray();

            this.EnterScope(ODataCollectionReaderState.CollectionStart, collectionStart);

            return(true);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Returns the annotation in the OData metadata namespace with the specified <paramref name="localName" />.
        /// </summary>
        /// <param name="model">The <see cref="IEdmModel"/> containing the annotation.</param>
        /// <param name="annotatable">The <see cref="IEdmElement"/> to get the annotation from.</param>
        /// <param name="localName">The local name of the annotation to find.</param>
        /// <param name="value">The value of the annotation in the OData metadata namespace and with the specified <paramref name="localName"/>.</param>
        /// <returns>true if an annotation with the specified local name was found; otherwise false.</returns>
        internal static bool TryGetODataAnnotation(this IEdmModel model, IEdmElement annotatable, string localName, out string value)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(model != null, "model != null");
            Debug.Assert(annotatable != null, "annotatable != null");
            Debug.Assert(!string.IsNullOrEmpty(localName), "!string.IsNullOrEmpty(localName)");

            object annotationValue = model.GetAnnotationValue(annotatable, AtomConstants.ODataMetadataNamespace, localName);

            if (annotationValue == null)
            {
                value = null;
                return(false);
            }

            IEdmStringValue annotationStringValue = annotationValue as IEdmStringValue;

            if (annotationStringValue == null)
            {
                // invalid annotation type found
                throw new ODataException(Strings.ODataAtomWriterMetadataUtils_InvalidAnnotationValue(localName, annotationValue.GetType().FullName));
            }

            value = annotationStringValue.Value;
            return(true);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Parses a segment; a expression that is followed by a slash.
        /// </summary>
        /// <param name="parent">The parent of the segment node.</param>
        /// <returns>The lexical token representing the segment.</returns>
        private PathSegmentToken ParseSegment(PathSegmentToken parent)
        {
            string propertyName;

            if (this.Lexer.PeekNextToken().Kind == ExpressionTokenKind.Dot)
            {
                propertyName = this.Lexer.ReadDottedIdentifier(this.isSelect);
            }
            else if (this.Lexer.CurrentToken.Kind == ExpressionTokenKind.Star)
            {
                if (this.Lexer.PeekNextToken().Kind == ExpressionTokenKind.Slash)
                {
                    throw new ODataException(ODataErrorStrings.ExpressionToken_IdentifierExpected(this.Lexer.Position));
                }

                propertyName = this.Lexer.CurrentToken.Text;
                this.Lexer.NextToken();
            }
            else
            {
                propertyName = this.Lexer.CurrentToken.GetIdentifier();
                this.Lexer.NextToken();
            }

            return(new NonSystemToken(propertyName, null, parent));
        }
Exemplo n.º 6
0
        /// <summary>
        /// Bind this function call token as a built in function
        /// </summary>
        /// <param name="functionCallToken">the function call token to bidn</param>
        /// <param name="state">the current state of the binding algorithm</param>
        /// <param name="argumentNodes">list of semantically bound arguments</param>
        /// <returns>A function call node bound to this function.</returns>
        private static QueryNode BindAsBuiltInFunction(FunctionCallToken functionCallToken, BindingState state, List <QueryNode> argumentNodes)
        {
            if (functionCallToken.Source != null)
            {
                // the parent must be null for a built in function.
                throw new ODataException(ODataErrorStrings.FunctionCallBinder_BuiltInFunctionMustHaveHaveNullParent(functionCallToken.Name));
            }

            // There are some functions (IsOf and Cast for example) that don't necessarily need to be bound to a BuiltInFunctionSignature,
            // for these, we just Bind them directly to a SingleValueFunctionCallNode
            if (IsUnboundFunction(functionCallToken.Name))
            {
                return(CreateUnboundFunctionNode(functionCallToken, argumentNodes, state));
            }

            // Do some validation and get potential built-in functions that could match what we saw
            FunctionSignatureWithReturnType[] signatures = GetBuiltInFunctionSignatures(functionCallToken.Name);
            IEdmTypeReference[] argumentTypes            = EnsureArgumentsAreSingleValue(functionCallToken.Name, argumentNodes);

            FunctionSignatureWithReturnType signature = MatchSignatureToBuiltInFunction(functionCallToken.Name, argumentTypes, signatures);

            if (signature.ReturnType != null)
            {
                TypePromoteArguments(signature, argumentNodes);
            }

            IEdmTypeReference returnType = signature.ReturnType;

            return(new SingleValueFunctionCallNode(functionCallToken.Name, new ReadOnlyCollection <QueryNode>(argumentNodes), returnType));
        }
Exemplo n.º 7
0
        /// <summary>
        /// Ensure that this expand path contains only valid segment types.
        /// </summary>
        /// <exception cref="ODataException">Throws if this list of segments doesn't match the requirements for a $expand</exception>
        private void ValidatePath()
        {
            int  index        = 0;
            bool foundNavProp = false;

            foreach (ODataPathSegment segment in this)
            {
                if (segment is TypeSegment)
                {
                    if (index == this.Count - 1)
                    {
                        throw new ODataException(ODataErrorStrings.ODataExpandPath_OnlyLastSegmentMustBeNavigationProperty);
                    }
                }
                else if (segment is NavigationPropertySegment)
                {
                    if (index < this.Count - 1 || foundNavProp)
                    {
                        throw new ODataException(ODataErrorStrings.ODataExpandPath_OnlyLastSegmentMustBeNavigationProperty);
                    }

                    foundNavProp = true;
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.ODataExpandPath_InvalidExpandPathSegment(segment.GetType().Name));
                }

                index++;
            }
        }
 /// <summary>
 /// Validate the Metadata Uri Fragment is @Element for a non $links metadata uri, throws if its not correct
 /// </summary>
 /// <param name="elementSelector">Element selector.</param>
 private void ValidateMetadataUriFragmentItemSelector(string elementSelector)
 {
     if (string.CompareOrdinal(JsonLightConstants.MetadataUriFragmentItemSelector, elementSelector) != 0)
     {
         throw new ODataException(ODataErrorStrings.ODataJsonLightMetadataUriParser_InvalidEntityWithTypeCastUriSuffix(UriUtilsCommon.UriToString(this.parseResult.MetadataUri), elementSelector, JsonLightConstants.MetadataUriFragmentItemSelector));
     }
 }
Exemplo n.º 9
0
        /// <summary>
        /// Returns the type of the property on the specified type.
        /// </summary>
        /// <param name="type">The type to look for the property on.</param>
        /// <param name="propertyName">The name of the property to look for.</param>
        /// <returns>The type of the property specified.</returns>
        private static IEdmTypeReference GetPropertyType(IEdmType type, string propertyName)
        {
            Debug.Assert(propertyName != null, "propertyName != null");

            IEdmStructuredType structuredType = type as IEdmStructuredType;
            IEdmProperty       property       = structuredType == null ? null : structuredType.FindProperty(propertyName);

            if (property != null)
            {
                IEdmTypeReference propertyType = property.Type;
                if (propertyType.IsNonEntityCollectionType())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_CollectionPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }

                if (propertyType.IsStream())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_StreamPropertyCannotBeMapped(propertyName, type.ODataFullName()));
                }

                if (propertyType.IsSpatial())
                {
                    throw new ODataException(ODataErrorStrings.EpmSourceTree_SpatialTypeCannotBeMapped(propertyName, type.ODataFullName()));
                }

                return(property.Type);
            }

            if (type != null && !type.IsOpenType())
            {
                throw new ODataException(ODataErrorStrings.EpmSourceTree_MissingPropertyOnType(propertyName, type.ODataFullName()));
            }

            return(null);
        }
Exemplo n.º 10
0
        /// <summary>
        /// Reads an item in the collection.
        /// </summary>
        /// <param name="expectedItemType">The expected type of the item to read.</param>
        /// <param name="collectionValidator">The collection validator instance if no expected item type has been specified; otherwise null.</param>
        /// <returns>The value of the collection item that was read; this can be an ODataComplexValue, a primitive value or 'null'.</returns>
        /// <remarks>
        /// Pre-Condition:  XmlNodeType.Element    - The start element node of the item in the collection.
        /// Post-Condition: Any                    - The next node after the end tag of the item.
        /// </remarks>
        internal object ReadCollectionItem(IEdmTypeReference expectedItemType, CollectionWithoutExpectedTypeValidator collectionValidator)
        {
            DebugUtils.CheckNoExternalCallers();
            this.XmlReader.AssertNotBuffering();
            this.AssertXmlCondition(XmlNodeType.Element);

            // the caller should guarantee that we are reading elements in the OData namespace or the custom namespace specified through the reader settings.
            Debug.Assert(this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace), "The 'element' node should be in the OData Namespace or in the user specified Namespace");

            // make sure that the item is named as 'element'.
            if (!this.XmlReader.LocalNameEquals(this.ODataCollectionItemElementName))
            {
                throw new ODataException(ODataErrorStrings.ODataAtomCollectionDeserializer_WrongCollectionItemElementName(this.XmlReader.LocalName, this.XmlReader.ODataNamespace));
            }

            // We don't support EPM for collections so it is fine to say that EPM is not present
            object item = this.ReadNonEntityValue(expectedItemType, this.duplicatePropertyNamesChecker, collectionValidator, /*validateNullValue*/ true, /* epmPresent */ false);

            // read over the end tag of the element or the start tag if the element was empty.
            this.XmlReader.Read();

            this.XmlReader.AssertNotBuffering();

            return(item);
        }
        /// <summary>
        /// This method creates and reads the property from the input and
        /// returns an <see cref="ODataProperty"/> representing the read property.
        /// </summary>
        /// <param name="expectedProperty">The <see cref="IEdmProperty"/> producing the property to be read.</param>
        /// <param name="expectedPropertyTypeReference">The expected type of the property to read.</param>
        /// <returns>An <see cref="ODataProperty"/> representing the read property.</returns>
        internal ODataProperty ReadTopLevelProperty(IEdmStructuralProperty expectedProperty, IEdmTypeReference expectedPropertyTypeReference)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(
                expectedPropertyTypeReference == null || !expectedPropertyTypeReference.IsODataEntityTypeKind(),
                "If the expected type is specified it must not be an entity type.");
            Debug.Assert(this.XmlReader != null, "this.xmlReader != null");

            this.ReadPayloadStart();
            Debug.Assert(this.XmlReader.NodeType == XmlNodeType.Element, "The XML reader must be positioned on an Element.");

            // For compatibility with WCF DS Server we need to be able to read the property element in any namespace, not just the OData namespace.
            if (!this.UseServerFormatBehavior && !this.XmlReader.NamespaceEquals(this.XmlReader.ODataNamespace))
            {
                throw new ODataException(ODataErrorStrings.ODataAtomPropertyAndValueDeserializer_TopLevelPropertyElementWrongNamespace(this.XmlReader.NamespaceURI, this.XmlReader.ODataNamespace));
            }

            // this is a top level property so EPM does not apply hence it is safe to say that EPM is not present
            this.AssertRecursionDepthIsZero();
            string        expectedPropertyName = ReaderUtils.GetExpectedPropertyName(expectedProperty);
            ODataProperty property             = this.ReadProperty(
                expectedPropertyName,
                expectedPropertyTypeReference,
                /*nullValueReadBehaviorKind*/ ODataNullValueBehaviorKind.Default,
                /* epmPresent */ false);

            this.AssertRecursionDepthIsZero();

            Debug.Assert(property != null, "If we don't ignore null values the property must not be null.");

            this.ReadPayloadEnd();

            return(property);
        }
        /// <summary>
        /// Read a query option from the lexer.
        /// </summary>
        /// <returns>the query option as a string.</returns>
        private string ReadQueryOption()
        {
            if (this.Lexer.CurrentToken.Kind != ExpressionTokenKind.Equal)
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.Lexer.ExpressionText));
            }

            // a query option looks like
            // <anytext>;

            // advance the lexer to the beginning of the query option.
            this.Lexer.NextToken();

            // get the full text from the current location onward
            string textToReturn = this.Lexer.ExpressionText.Substring(this.Lexer.Position);

            textToReturn = textToReturn.Split(';').First();

            while (this.Lexer.PeekNextToken().Kind != ExpressionTokenKind.SemiColon)
            {
                this.Lexer.NextToken();
            }

            // next token is a semicolon, so advance there
            this.Lexer.NextToken();
            return(textToReturn);
        }
Exemplo n.º 13
0
        /// <summary>
        /// Handles the start of primary expressions.
        /// </summary>
        /// <returns>The lexical token representing the expression.</returns>
        private QueryToken ParsePrimaryStart()
        {
            switch (this.lexer.CurrentToken.Kind)
            {
            case ExpressionTokenKind.Identifier:
            {
                IdentifierTokenizer identifierTokenizer = new IdentifierTokenizer(this.parameters, new FunctionCallParser(this.lexer, this.ParseExpression));
                return(identifierTokenizer.ParseIdentifier(null));
            }

            case ExpressionTokenKind.OpenParen:
            {
                return(this.ParseParenExpression());
            }

            case ExpressionTokenKind.Star:
            {
                IdentifierTokenizer identifierTokenizer = new IdentifierTokenizer(this.parameters, new FunctionCallParser(this.lexer, this.ParseExpression));
                return(identifierTokenizer.ParseStarMemberAccess(null));
            }

            default:
            {
                QueryToken primitiveLiteralToken = TryParseLiteral(this.lexer);
                if (primitiveLiteralToken == null)
                {
                    throw ParseError(ODataErrorStrings.UriQueryExpressionParser_ExpressionExpected(this.lexer.CurrentToken.Position, this.lexer.ExpressionText));
                }

                return(primitiveLiteralToken);
            }
            }
        }
Exemplo n.º 14
0
        /// <summary>
        /// Compute the result type of a binary operator based on the type of its operands and the operator kind.
        /// </summary>
        /// <param name="typeReference">The type reference of the operators.</param>
        /// <param name="operatorKind">The kind of operator.</param>
        /// <returns>The result type reference of the binary operator.</returns>
        internal static IEdmPrimitiveTypeReference GetBinaryOperatorResultType(IEdmPrimitiveTypeReference typeReference, BinaryOperatorKind operatorKind)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(typeReference != null, "type != null");

            switch (operatorKind)
            {
            case BinaryOperatorKind.Or:                     // fall through
            case BinaryOperatorKind.And:                    // fall through
            case BinaryOperatorKind.Equal:                  // fall through
            case BinaryOperatorKind.NotEqual:               // fall through
            case BinaryOperatorKind.GreaterThan:            // fall through
            case BinaryOperatorKind.GreaterThanOrEqual:     // fall through
            case BinaryOperatorKind.LessThan:               // fall through
            case BinaryOperatorKind.LessThanOrEqual:
                return(EdmCoreModel.Instance.GetBoolean(typeReference.IsNullable));

            case BinaryOperatorKind.Add:            // fall through
            case BinaryOperatorKind.Subtract:       // fall through
            case BinaryOperatorKind.Multiply:       // fall through
            case BinaryOperatorKind.Divide:         // fall through
            case BinaryOperatorKind.Modulo:
                return(typeReference);

            default:
                throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.QueryNodeUtils_BinaryOperatorResultType_UnreachableCodepath));
            }
        }
Exemplo n.º 15
0
        /// <summary>
        /// Creates a text ATOM value.
        /// </summary>
        /// <param name="textValue">The text value to use.</param>
        /// <param name="contentKind">The content kind of the value.</param>
        /// <returns>The Atom text value.</returns>
        private static AtomTextConstruct CreateAtomTextConstruct(string textValue, SyndicationTextContentKind contentKind)
        {
            AtomTextConstructKind kind;

            switch (contentKind)
            {
            case SyndicationTextContentKind.Plaintext:
                kind = AtomTextConstructKind.Text;
                break;

            case SyndicationTextContentKind.Html:
                kind = AtomTextConstructKind.Html;
                break;

            case SyndicationTextContentKind.Xhtml:
                kind = AtomTextConstructKind.Xhtml;
                break;

            default:
                throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmSyndicationWriter_CreateAtomTextConstruct));
            }

            return(new AtomTextConstruct
            {
                Kind = kind,
                Text = textValue,
            });
        }
Exemplo n.º 16
0
        /// <summary>
        /// Converts the given <paramref name="uri"/> Uri to a string.
        /// If the provided baseUri is not null and is a base Uri of the <paramref name="uri"/> Uri
        /// the method returns the string form of the relative Uri.
        /// </summary>
        /// <param name="uri">The Uri to convert.</param>
        /// <param name="failOnRelativeUriWithoutBaseUri">If set to true then this method will fail if the uri specified by <paramref name="uri"/> is relative
        /// and no base uri is specified.</param>
        /// <returns>The string form of the <paramref name="uri"/> Uri. If the Uri is absolute it returns the
        /// string form of the <paramref name="uri"/>. If the <paramref name="uri"/> Uri is not absolute
        /// it returns the original string of the Uri.</returns>
        internal string UriToUrlAttributeValue(Uri uri, bool failOnRelativeUriWithoutBaseUri)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(uri != null, "uri != null");

            if (this.UrlResolver != null)
            {
                // The resolver returns 'null' if no custom resolution is desired.
                Uri resultUri = this.UrlResolver.ResolveUrl(this.MessageWriterSettings.BaseUri, uri);
                if (resultUri != null)
                {
                    return(UriUtilsCommon.UriToString(resultUri));
                }
            }

            if (!uri.IsAbsoluteUri)
            {
                // NOTE: the only URIs that are allowed to be relative (e.g., failOnRelativeUriWithoutBaseUri is false)
                //       are metadata URIs in operations; for such metadata URIs there is no base URI.
                if (this.MessageWriterSettings.BaseUri == null && failOnRelativeUriWithoutBaseUri)
                {
                    throw new ODataException(
                              ODataErrorStrings.ODataWriter_RelativeUriUsedWithoutBaseUriSpecified(UriUtilsCommon.UriToString(uri)));
                }

                uri = UriUtils.EnsureEscapedRelativeUri(uri);
            }

            return(UriUtilsCommon.UriToString(uri));
        }
Exemplo n.º 17
0
        /// <summary>
        /// Build a segment from a token.
        /// </summary>
        /// <param name="tokenIn">the token to bind</param>
        /// <param name="model">The model.</param>
        /// <param name="entityType">the entity type of the current scope based on type segments.</param>
        /// <returns>The segment created from the token.</returns>
        public static ODataPathSegment ConvertNonTypeTokenToSegment(PathSegmentToken tokenIn, IEdmModel model, IEdmEntityType entityType)
        {
            ODataPathSegment nextSegment;

            if (TryBindAsDeclaredProperty(tokenIn, entityType, out nextSegment))
            {
                return(nextSegment);
            }

            // for open types, operations must be container-qualified, and because the token type indicates it was not a .-seperated identifier, we should not try to look up operations.
            if (!entityType.IsOpen || tokenIn.IsNamespaceOrContainerQualified())
            {
                if (TryBindAsOperation(tokenIn, model, entityType, out nextSegment))
                {
                    return(nextSegment);
                }
            }

            if (entityType.IsOpen)
            {
                return(new OpenPropertySegment(tokenIn.Identifier));
            }

            throw new ODataException(ODataErrorStrings.MetadataBinder_PropertyNotDeclared(entityType.FullName(), tokenIn.Identifier));
        }
Exemplo n.º 18
0
        /// <summary>
        /// Resolves a name to an <see cref="IEdmFunctionImport"/> instance.
        /// </summary>
        /// <param name="model">The model to resolve the name against.</param>
        /// <param name="operationName">The name of the service operation to look up.</param>
        /// <returns>An <see cref="IEdmFunctionImport"/> instance with the specified <paramref name="operationName"/> or null if no such service operation exists.</returns>
        public static IEdmFunctionImport TryResolveServiceOperation(this IEdmModel model, string operationName)
        {
            ExceptionUtils.CheckArgumentNotNull(model, "model");
            ExceptionUtils.CheckArgumentStringNotNullOrEmpty(operationName, "operationName");

            IEdmFunctionImport functionImport = null;

            foreach (IEdmFunctionImport import in model.ResolveFunctionImports(operationName))
            {
                if (model.IsServiceOperation(import))
                {
                    if (functionImport == null)
                    {
                        functionImport = import;
                    }
                    else
                    {
                        throw new ODataException(
                                  ODataErrorStrings.ODataQueryUtils_FoundMultipleServiceOperations(operationName));
                    }
                }
            }

            return(functionImport);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Gets the correct set of function signatures for type promotion for a given binary operator.
        /// </summary>
        /// <param name="operatorKind">The operator kind to get the signatures for.</param>
        /// <returns>The set of signatures for the specified <paramref name="operatorKind"/>.</returns>
        private static FunctionSignature[] GetFunctionSignatures(BinaryOperatorKind operatorKind)
        {
            switch (operatorKind)
            {
            case BinaryOperatorKind.Or:         // fall through
            case BinaryOperatorKind.And:
                return(logicalSignatures);

            case BinaryOperatorKind.Equal:                  // fall through
            case BinaryOperatorKind.NotEqual:               // fall through
            case BinaryOperatorKind.GreaterThan:            // fall through
            case BinaryOperatorKind.GreaterThanOrEqual:     // fall through
            case BinaryOperatorKind.LessThan:               // fall through
            case BinaryOperatorKind.LessThanOrEqual:
                return(relationalSignatures);

            case BinaryOperatorKind.Add:                    // fall through
            case BinaryOperatorKind.Subtract:               // fall through
            case BinaryOperatorKind.Multiply:               // fall through
            case BinaryOperatorKind.Divide:                 // fall through
            case BinaryOperatorKind.Modulo:                 // fall through
                return(arithmeticSignatures);

            default:
                throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.TypePromotionUtils_GetFunctionSignatures_Binary_UnreachableCodepath));
            }
        }
Exemplo n.º 20
0
        /// <summary>
        /// Parses argument lists.
        /// </summary>
        /// <returns>The lexical tokens representing the arguments.</returns>
        public FunctionParameterToken[] ParseArgumentList()
        {
            if (this.Lexer.CurrentToken.Kind != ExpressionTokenKind.OpenParen)
            {
                throw new ODataException(ODataErrorStrings.UriQueryExpressionParser_OpenParenExpected(this.Lexer.CurrentToken.Position, this.Lexer.ExpressionText));
            }

            this.Lexer.NextToken();
            FunctionParameterToken[] arguments;
            if (this.Lexer.CurrentToken.Kind == ExpressionTokenKind.CloseParen)
            {
                arguments = FunctionParameterToken.EmptyParameterList;
            }
            else
            {
                arguments = this.ParseArguments();
            }

            if (this.Lexer.CurrentToken.Kind != ExpressionTokenKind.CloseParen)
            {
                throw new ODataException(ODataErrorStrings.UriQueryExpressionParser_CloseParenOrCommaExpected(this.Lexer.CurrentToken.Position, this.Lexer.ExpressionText));
            }

            this.Lexer.NextToken();
            return(arguments);
        }
Exemplo n.º 21
0
        /// <summary>
        /// Binds a DottedIdentifierToken and it's parent node (if needed).
        /// </summary>
        /// <param name="dottedIdentifierToken">Token to bind to metadata.</param>
        /// <param name="state">State of the Binding.</param>
        /// <returns>A bound node representing the cast.</returns>
        internal QueryNode BindDottedIdentifier(DottedIdentifierToken dottedIdentifierToken, BindingState state)
        {
            DebugUtils.CheckNoExternalCallers();
            ExceptionUtils.CheckArgumentNotNull(dottedIdentifierToken, "castToken");
            ExceptionUtils.CheckArgumentNotNull(state, "state");

            QueryNode parent;
            IEdmType  parentType;

            if (dottedIdentifierToken.NextToken == null)
            {
                parent     = NodeFactory.CreateRangeVariableReferenceNode(state.ImplicitRangeVariable);
                parentType = state.ImplicitRangeVariable.TypeReference.Definition;
            }
            else
            {
                parent     = this.bindMethod(dottedIdentifierToken.NextToken);
                parentType = parent.GetEdmType();
            }

            SingleEntityNode parentAsSingleValue = parent as SingleEntityNode;

            IEdmSchemaType childType       = UriEdmHelpers.FindTypeFromModel(state.Model, dottedIdentifierToken.Identifier);
            IEdmEntityType childEntityType = childType as IEdmEntityType;

            if (childEntityType == null)
            {
                FunctionCallBinder functionCallBinder = new FunctionCallBinder(bindMethod);
                QueryNode          functionCallNode;
                if (functionCallBinder.TryBindDottedIdentifierAsFunctionCall(dottedIdentifierToken, parentAsSingleValue, state, out functionCallNode))
                {
                    return(functionCallNode);
                }
                else
                {
                    throw new ODataException(ODataErrorStrings.CastBinder_ChildTypeIsNotEntity(dottedIdentifierToken.Identifier));
                }
            }

            // Check whether childType is a derived type of the type of its parent node
            UriEdmHelpers.CheckRelatedTo(parentType, childType);

            EntityCollectionNode parentAsCollection = parent as EntityCollectionNode;

            if (parentAsCollection != null)
            {
                return(new EntityCollectionCastNode(parentAsCollection, childEntityType));
            }

            // parent can be null for casts on the implicit parameter; this is OK
            if (parent == null)
            {
                return(new SingleEntityCastNode(null, childEntityType));
            }

            Debug.Assert(parentAsSingleValue != null, "If parent of the cast node was not collection, it should be a single value.");
            return(new SingleEntityCastNode(parentAsSingleValue, childEntityType));
        }
Exemplo n.º 22
0
        /// <summary>
        /// Validates that the count property in an OData-owned object wrapper is valid.
        /// </summary>
        /// <param name="propertyValue">The value of the property.</param>
        internal static void ValidateCountPropertyInEntityReferenceLinks(long?propertyValue)
        {
            DebugUtils.CheckNoExternalCallers();

            if (!propertyValue.HasValue)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_EntityReferenceLinksInlineCountWithNullValue(JsonConstants.ODataCountName));
            }
        }
Exemplo n.º 23
0
        /// <summary>
        /// Parses the Any/All portion of the query
        /// </summary>
        /// <param name="parent">The parent of the Any/All node.</param>
        /// <param name="isAny">Denotes whether an Any or All is to be parsed.</param>
        /// <returns>The lexical token representing the Any/All query.</returns>
        private QueryToken ParseAnyAll(QueryToken parent, bool isAny)
        {
            this.lexer.NextToken();
            if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.OpenParen)
            {
                throw ParseError(ODataErrorStrings.UriQueryExpressionParser_OpenParenExpected(this.lexer.CurrentToken.Position, this.lexer.ExpressionText));
            }

            this.lexer.NextToken();

            // When faced with Any(), return the same thing as if you encountered Any(a : true)
            if (this.lexer.CurrentToken.Kind == ExpressionTokenKind.CloseParen)
            {
                this.lexer.NextToken();
                if (isAny)
                {
                    return(new AnyToken(new LiteralToken(true, "True"), null, parent));
                }
                else
                {
                    return(new AllToken(new LiteralToken(true, "True"), null, parent));
                }
            }

            string parameter = this.lexer.CurrentToken.GetIdentifier();

            if (!this.parameters.Add(parameter))
            {
                throw ParseError(ODataErrorStrings.UriQueryExpressionParser_RangeVariableAlreadyDeclared(parameter));
            }

            // read the ':' separating the range variable from the expression.
            this.lexer.NextToken();
            this.lexer.ValidateToken(ExpressionTokenKind.Colon);

            this.lexer.NextToken();
            QueryToken expr = this.ParseExpression();

            if (this.lexer.CurrentToken.Kind != ExpressionTokenKind.CloseParen)
            {
                throw ParseError(ODataErrorStrings.UriQueryExpressionParser_CloseParenOrCommaExpected(this.lexer.CurrentToken.Position, this.lexer.ExpressionText));
            }

            // forget about the range variable after parsing the expression for this lambda.
            this.parameters.Remove(parameter);

            this.lexer.NextToken();
            if (isAny)
            {
                return(new AnyToken(expr, parameter, parent));
            }
            else
            {
                return(new AllToken(expr, parameter, parent));
            }
        }
Exemplo n.º 24
0
        /// <summary>
        /// Tries to parse a collection of function parameters. Allows path and filter to share the core algorithm while representing parameters differently.
        /// </summary>
        /// <param name="lexer">The lexer to read from.</param>
        /// <param name="endTokenKind">The token kind that marks the end of the parameters.</param>
        /// <param name="splitParameters">The parameters if they were successfully split.</param>
        /// <returns>Whether the parameters could be split.</returns>
        private static bool TrySplitFunctionParameters(this ExpressionLexer lexer, ExpressionTokenKind endTokenKind, out ICollection <FunctionParameterToken> splitParameters)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(lexer != null, "lexer != null");

            var parameters = new List <FunctionParameterToken>();

            splitParameters = parameters;

            ExpressionToken currentToken = lexer.CurrentToken;

            if (currentToken.Kind == endTokenKind)
            {
                return(true);
            }

            if (currentToken.Kind != ExpressionTokenKind.Identifier || lexer.PeekNextToken().Kind != ExpressionTokenKind.Equal)
            {
                return(false);
            }

            while (currentToken.Kind != endTokenKind)
            {
                lexer.ValidateToken(ExpressionTokenKind.Identifier);
                string identifier = lexer.CurrentToken.GetIdentifier();
                lexer.NextToken();

                lexer.ValidateToken(ExpressionTokenKind.Equal);
                lexer.NextToken();

                QueryToken parameterValue;
                if (!TryCreateParameterValueToken(lexer.CurrentToken, out parameterValue))
                {
                    throw new ODataException(ODataErrorStrings.ExpressionLexer_SyntaxError(lexer.Position, lexer.ExpressionText));
                }

                parameters.Add(new FunctionParameterToken(identifier, parameterValue));

                // Read the next parameterToken. We should be at the end, or find
                // we have a comma followed by something.
                lexer.NextToken();
                currentToken = lexer.CurrentToken;
                if (currentToken.Kind == ExpressionTokenKind.Comma)
                {
                    lexer.NextToken();
                    currentToken = lexer.CurrentToken;
                    if (currentToken.Kind == endTokenKind)
                    {
                        // Trailing comma.
                        throw new ODataException(ODataErrorStrings.ExpressionLexer_SyntaxError(lexer.Position, lexer.ExpressionText));
                    }
                }
            }

            return(true);
        }
Exemplo n.º 25
0
        private static DateTimeOffset CreateDateTimeValue(object propertyValue, SyndicationItemProperty targetProperty, ODataWriterBehavior writerBehavior)
        {
            Debug.Assert(
                writerBehavior.FormatBehaviorKind != ODataBehaviorKind.WcfDataServicesClient,
                "CreateDateTimeValue should not be used in WCF DS client mode.");

            if (propertyValue == null)
            {
                return(DateTimeOffset.Now);
            }

            if (propertyValue is DateTimeOffset)
            {
                return((DateTimeOffset)propertyValue);
            }

            if (propertyValue is DateTime)
            {
                // DateTimeOffset takes care of DateTimes of Unspecified kind so we won't end up
                // with datetime without timezone info mapped to atom:updated or atom:published element.
                return(new DateTimeOffset((DateTime)propertyValue));
            }

            string stringValue = propertyValue as string;

            if (stringValue != null)
            {
                DateTimeOffset date;
                if (!DateTimeOffset.TryParse(stringValue, out date))
                {
                    DateTime result;
                    if (!DateTime.TryParse(stringValue, out result))
                    {
                        throw new ODataException(ODataErrorStrings.EpmSyndicationWriter_DateTimePropertyCanNotBeConverted(targetProperty.ToString()));
                    }

                    return(new DateTimeOffset(result));
                }

                return(date);
            }

            try
            {
                return(new DateTimeOffset(Convert.ToDateTime(propertyValue, CultureInfo.InvariantCulture)));
            }
            catch (Exception e)
            {
                if (!ExceptionUtils.IsCatchableExceptionType(e))
                {
                    throw;
                }

                throw new ODataException(ODataErrorStrings.EpmSyndicationWriter_DateTimePropertyCanNotBeConverted(targetProperty.ToString()));
            }
        }
Exemplo n.º 26
0
        /// <summary>
        /// Validates that the property in feed wrapper is valid.
        /// </summary>
        /// <param name="propertyValue">The value of the property.</param>
        /// <param name="propertyName">The name of the property (used for error reporting).</param>
        internal static void ValidateFeedProperty(object propertyValue, string propertyName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(!string.IsNullOrEmpty(propertyName), "!string.IsNullOrEmpty(propertyName)");

            if (propertyValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonReaderUtils_FeedPropertyWithNullValue(propertyName));
            }
        }
Exemplo n.º 27
0
        /// <summary>
        /// Build the list of expand options
        /// Depends on whether options are allowed or not.
        /// </summary>
        /// <param name="isInnerTerm">is this an inner expand term</param>
        /// <param name="pathToken">the current level token, as a PathToken</param>
        /// <returns>An expand term token based on the path token.</returns>
        internal override ExpandTermToken BuildExpandTermToken(bool isInnerTerm, PathSegmentToken pathToken)
        {
            DebugUtils.CheckNoExternalCallers();
            if (this.IsNotEndOfTerm(false))
            {
                throw new ODataException(ODataErrorStrings.UriSelectParser_TermIsNotValid(this.Lexer.ExpressionText));
            }

            return(new ExpandTermToken(pathToken));
        }
Exemplo n.º 28
0
        /// <summary>
        /// Parses * (all member) access at the beginning of a select expression.
        /// </summary>
        /// <param name="instance">Instance being accessed.</param>
        /// <returns>The lexical token representing the expression.</returns>
        public QueryToken ParseStarMemberAccess(QueryToken instance)
        {
            if (this.lexer.CurrentToken.Text != UriQueryConstants.Star)
            {
                throw ParseError(ODataErrorStrings.UriQueryExpressionParser_CannotCreateStarTokenFromNonStar(this.lexer.CurrentToken.Text));
            }

            this.lexer.NextToken();
            return(new StarToken(instance));
        }
Exemplo n.º 29
0
        /// <summary>
        /// Validates that the annotation string value is valid.
        /// </summary>
        /// <param name="propertyValue">The value of the annotation.</param>
        /// <param name="annotationName">The name of the (instance or property) annotation (used for error reporting).</param>
        internal static void ValidateAnnotationStringValue(string propertyValue, string annotationName)
        {
            DebugUtils.CheckNoExternalCallers();
            Debug.Assert(!string.IsNullOrEmpty(annotationName), "!string.IsNullOrEmpty(annotationName)");

            if (propertyValue == null)
            {
                throw new ODataException(ODataErrorStrings.ODataJsonLightReaderUtils_AnnotationWithNullValue(annotationName));
            }
        }
Exemplo n.º 30
0
        /// <summary>
        /// Reads EPM values from a person construct (author or contributor).
        /// </summary>
        /// <param name="targetList">The target list, this can be either a list of properties (on entry or complex value),
        /// or a list of items (for a collection of primitive types).</param>
        /// <param name="targetTypeReference">The type of the value on which to set the property (can be entity, complex or primitive).</param>
        /// <param name="targetSegment">The target segment which points to either author or contributor element.</param>
        /// <param name="personMetadata">The person ATOM metadata to read from.</param>
        private void ReadPersonEpm(ReadOnlyEnumerable <ODataProperty> targetList, IEdmTypeReference targetTypeReference, EpmTargetPathSegment targetSegment, AtomPersonMetadata personMetadata)
        {
            Debug.Assert(targetList != null, "targetList != null");
            Debug.Assert(targetTypeReference != null, "targetTypeReference != null");
            Debug.Assert(targetSegment != null, "targetSegment != null");
            Debug.Assert(
                targetSegment.SegmentName == AtomConstants.AtomAuthorElementName || targetSegment.SegmentName == AtomConstants.AtomContributorElementName,
                "targetSegment must be author or contributor.");
            Debug.Assert(personMetadata != null, "personMetadata != null");

            foreach (EpmTargetPathSegment subSegment in targetSegment.SubSegments)
            {
                Debug.Assert(subSegment.HasContent, "sub segment of author segment must have content, there are no subsegments which don't have content under author.");
                Debug.Assert(
                    subSegment.EpmInfo != null && subSegment.EpmInfo.Attribute != null && subSegment.EpmInfo.Attribute.TargetSyndicationItem != SyndicationItemProperty.CustomProperty,
                    "We should never find a subsegment without EPM attribute or for custom mapping when writing syndication person EPM.");
                switch (subSegment.EpmInfo.Attribute.TargetSyndicationItem)
                {
                case SyndicationItemProperty.AuthorName:
                case SyndicationItemProperty.ContributorName:
                    // Note that person name can never specify true null in EPM, since it can't have the m:null attribute on it.
                    string personName = personMetadata.Name;
                    if (personName != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personName);
                    }

                    break;

                case SyndicationItemProperty.AuthorEmail:
                case SyndicationItemProperty.ContributorEmail:
                    string personEmail = personMetadata.Email;
                    if (personEmail != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personEmail);
                    }

                    break;

                case SyndicationItemProperty.AuthorUri:
                case SyndicationItemProperty.ContributorUri:
                    string personUri = personMetadata.UriFromEpm;
                    if (personUri != null)
                    {
                        this.SetEpmValue(targetList, targetTypeReference, subSegment.EpmInfo, personUri);
                    }

                    break;

                default:
                    // Unhandled EpmTargetPathSegment.SegmentName.
                    throw new ODataException(ODataErrorStrings.General_InternalError(InternalErrorCodes.EpmSyndicationReader_ReadPersonEpm));
                }
            }
        }