protected virtual CsdlTypeReference ParseTypeReference(string typeString, XmlElementValueCollection childValues, CsdlLocation parentLocation, Optionality typeInfoOptionality) { bool isNullable = OptionalBoolean(CsdlConstants.Attribute_Nullable) ?? CsdlConstants.Default_Nullable; CsdlTypeReference elementType = null; if (typeString != null) { string[] typeInformation = typeString.Split(new char[] { '(', ')' }); string typeName = typeInformation[0]; switch (typeName) { case CsdlConstants.Value_Collection: { string elementTypeName = typeInformation.Length > 1 ? typeInformation[1] : typeString; elementType = new CsdlExpressionTypeReference( new CsdlCollectionType( this.ParseNamedTypeReference(elementTypeName, isNullable, parentLocation), parentLocation), isNullable, parentLocation); } break; case CsdlConstants.Value_Ref: { string elementTypeName = typeInformation.Length > 1 ? typeInformation[1] : typeString; elementType = new CsdlExpressionTypeReference( new CsdlEntityReferenceType( this.ParseNamedTypeReference(elementTypeName, isNullable, parentLocation), parentLocation), CsdlConstants.Default_Nullable, parentLocation); } break; default: elementType = this.ParseNamedTypeReference(typeName, isNullable, parentLocation); break; } } else if (childValues != null) { elementType = childValues.ValuesOfType <CsdlTypeReference>().FirstOrDefault(); } if (elementType == null && typeInfoOptionality == Optionality.Required) { if (childValues != null) { // If childValues is null, then it is the case when a required type attribute was expected. // In this case, we do not report the error as it should already be reported by EdmXmlDocumentParser.RequiredType method. this.ReportError(parentLocation, EdmErrorCode.MissingType, Edm.Strings.CsdlParser_MissingTypeAttributeOrElement); } else { Debug.Assert(this.Errors.Any(), "There should be an error reported for the missing required type attribute."); } elementType = new CsdlNamedTypeReference(String.Empty, isNullable, parentLocation); } return(elementType); }
public void ParseCsdlTermWithMembersWorksAsExpected() { string json = @"""ConformanceLevel"": { ""$Kind"": ""Term"", ""$Type"": ""Capabilities.ConformanceLevelType"", ""$Nullable"": true, ""$AppliesTo"": [ ""EntityContainer"" ], ""@Core.Description"": ""The conformance level achieved by this service"" }"; CsdlTerm term = ParseCsdlSchemaElement(json, SchemaJsonParser.ParseCsdlTermType); Assert.NotNull(term); Assert.Equal("ConformanceLevel", term.Name); Assert.Equal("EntityContainer", term.AppliesTo); Assert.Null(term.DefaultValue); Assert.True(term.HasVocabularyAnnotations); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(term.Type); Assert.Equal("Capabilities.ConformanceLevelType", namedType.FullName); Assert.True(namedType.IsNullable); CsdlAnnotation annotation = Assert.Single(term.VocabularyAnnotations); Assert.Equal("Core.Description", annotation.Term); Assert.IsType <CsdlConstantExpression>(annotation.Expression); }
public void ParseRecordExpressionWorksAsExpected() { string json = @" { ""@type"": ""org.example.person.Manager"", ""@Core.Description"": ""Annotation on record"", ""GivenName"": { ""$Path"": ""FirstName"" }, ""*****@*****.**"": ""Annotation on record member"", ""Surname"": { ""$Path"": ""LastName"" }, ""DirectSupervisor"": { ""$Path"": ""Manager"" }, ""CostCenter"": ""CostCenter Value"" }"; CsdlExpressionBase expressionBase = ParseExpression(json, out JsonParserContext context); Assert.NotEmpty(context.Errors); Assert.Equal(2, context.Errors.Count); Assert.Equal("A member at JSON path '[email protected]' is not supported.", context.Errors.First().ErrorMessage); Assert.Equal("A member at JSON path '[email protected]' is not supported.", context.Errors.Last().ErrorMessage); Assert.NotNull(expressionBase); CsdlRecordExpression recordExp = Assert.IsType <CsdlRecordExpression>(expressionBase); Assert.NotNull(recordExp.Type); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(recordExp.Type); Assert.Equal("org.example.person.Manager", namedType.FullName); Assert.NotNull(recordExp.PropertyValues); Assert.Equal(4, recordExp.PropertyValues.Count()); // GivenName CsdlPropertyValue propertyValue = recordExp.PropertyValues.FirstOrDefault(c => c.Property == "GivenName"); Assert.NotNull(propertyValue); Assert.IsType <CsdlPathExpression>(propertyValue.Expression); // Surname propertyValue = recordExp.PropertyValues.FirstOrDefault(c => c.Property == "Surname"); Assert.NotNull(propertyValue); Assert.IsType <CsdlPathExpression>(propertyValue.Expression); // DirectSupervisor propertyValue = recordExp.PropertyValues.FirstOrDefault(c => c.Property == "DirectSupervisor"); Assert.NotNull(propertyValue); Assert.IsType <CsdlPathExpression>(propertyValue.Expression); // DirectSupervisor propertyValue = recordExp.PropertyValues.FirstOrDefault(c => c.Property == "CostCenter"); Assert.NotNull(propertyValue); Assert.IsType <CsdlConstantExpression>(propertyValue.Expression); }
/// <summary> /// Parse the record expression expression using <see cref="JsonElement"/>. /// </summary> /// <param name="element">The input JSON element.</param> /// <param name="context">The parser context.</param> /// <returns>the built record expression.</returns> private static CsdlRecordExpression ParseRecordExpression(JsonElement element, JsonParserContext context) { Debug.Assert(context != null); // A record expression MAY specify the structured type of its result, which MUST be an entity type or complex type in scope. // If not explicitly specified, the type is derived from the expression’s context // The type of a record expression is represented as the @type control information // for example: "@type": "https://example.org/vocabs/person#org.example.person.Manager", // So far, ODL doesn't support the type "@type" with relative path, only supports like "#Model.VipCustomer", or without # // for 4.0, this name MUST be prefixed with the hash symbol (#); // or non-OData 4.0 payloads, built-in primitive type values SHOULD be represented without the hash symbol, // but consumers of 4.01 or greater payloads MUST support values with or without the hash symbol. CsdlTypeReference typeReference = null; if (element.TryGetProperty("@type", out JsonElement typeValue)) { // Try to build the type. The type should be "Complex type" or "Entity Type". string typeName = typeValue.ProcessProperty("@type", context, (e, c) => e.ParseAsString(c)); int index = typeName.IndexOf('#'); if (index >= 0) { typeName = typeName.Substring(index + 1); // remove the "#" } typeReference = new CsdlNamedTypeReference(typeName, true, context.Location()); } IList <CsdlPropertyValue> propertyValues = new List <CsdlPropertyValue>(); element.ParseAsObject(context, (propertyName, propertyValue) => { // skips the @type, because it's processed above. if (propertyName == "@type") { return; } // It MAY contain annotations for itself and its members. Annotations for record members are prefixed with the member name. // So far, it's not supported. So report non-fatal error for all the annotations on record. if (propertyName.IndexOf('@') != -1) { context.ReportError(EdmErrorCode.UnsupportedElement, Strings.CsdlJsonParser_UnsupportedJsonMember(context.Path)); return; } CsdlExpressionBase propertyValueExpression = ParseExpression(propertyValue, context); propertyValues.Add(new CsdlPropertyValue(propertyName, propertyValueExpression, context.Location())); }); return(new CsdlRecordExpression(typeReference, propertyValues, context.Location())); }
public void ParseCsdlOperationForActionWithMembersWorksAsExpected() { string json = @"""Approval"": [ { ""$Kind"": ""Action"", ""$IsBound"": true, ""$Parameter"": [ { ""$Name"": ""binding"", ""$Type"": ""self.Order"", ""$Nullable"": true } ] } ]"; IList <CsdlOperation> operations = ParseCsdlSchemaElement(json, SchemaJsonParser.TryParseCsdlOperationOverload); Assert.NotNull(operations); CsdlOperation operation = Assert.Single(operations); CsdlAction action = Assert.IsType <CsdlAction>(operation); Assert.Equal("Approval", action.Name); Assert.True(action.IsBound); Assert.Null(action.EntitySetPath); // Parameter CsdlOperationParameter parameter = Assert.Single(action.Parameters); Assert.Equal("binding", parameter.Name); Assert.False(parameter.IsOptional); Assert.Null(parameter.DefaultValue); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(parameter.Type); Assert.True(namedType.IsNullable); Assert.Equal("self.Order", namedType.FullName); // ReturnType Assert.Null(action.Return); }
public void ParseIsOfExpressionWorksAsExpected() { string json = @" { ""$IsOf"": { ""$Path"": ""FirstName"" }, ""$Type"": ""self.PreferredCustomer"", ""$Collection"": true }"; CsdlExpressionBase expressionBase = ParseExpression(json); Assert.NotNull(expressionBase); CsdlIsTypeExpression isTypeExp = Assert.IsType <CsdlIsTypeExpression>(expressionBase); Assert.NotNull(isTypeExp.Type); CsdlExpressionTypeReference expTypeReference = Assert.IsType <CsdlExpressionTypeReference>(isTypeExp.Type); CsdlCollectionType collectionType = Assert.IsType <CsdlCollectionType>(expTypeReference.TypeExpression); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(collectionType.ElementType); Assert.Equal("self.PreferredCustomer", namedType.FullName); Assert.NotNull(isTypeExp.Operand); Assert.IsType <CsdlPathExpression>(isTypeExp.Operand); }
public CsdlSemanticsNamedTypeReference(CsdlSemanticsSchema schema, CsdlNamedTypeReference reference) : base(reference) { this.schema = schema; this.reference = reference; }
public CsdlSemanticsTypeDefinitionReference(CsdlSemanticsSchema schema, CsdlNamedTypeReference reference) : base(schema, reference) { }
public void ParseCsdlComplexTypeWithMembersWorksAsExpected() { string json = @"""CountRestrictionsType"": { ""$Kind"": ""ComplexType"", ""Countable"": { ""$Type"": ""Edm.Boolean"", ""$DefaultValue"": true, ""@Core.Description"": ""Entities can be counted (only valid if targeting an entity set)"" }, ""NonCountableProperties"": { ""$Collection"": true, ""$Type"": ""Edm.PropertyPath"", ""@Core.Description"": ""Members of these collection properties cannot be counted"" }, ""NonCountableNavigationProperties"": { ""$Collection"": true, ""$Type"": ""Edm.NavigationPropertyPath"", ""@Core.Description"": ""Members of these navigation properties cannot be counted"" } }"; CsdlComplexType complexType = ParseCsdlSchemaElement(json, SchemaJsonParser.ParseCsdlComplexType); Assert.NotNull(complexType); Assert.Equal("CountRestrictionsType", complexType.Name); Assert.False(complexType.IsAbstract); Assert.False(complexType.IsOpen); Assert.Null(complexType.BaseTypeName); Assert.Empty(complexType.NavigationProperties); Assert.Equal(3, complexType.StructuralProperties.Count()); // Countable CsdlProperty countable = complexType.StructuralProperties.FirstOrDefault(p => p.Name == "Countable"); Assert.NotNull(countable); CsdlPrimitiveTypeReference primitiveType = Assert.IsType <CsdlPrimitiveTypeReference>(countable.Type); Assert.Equal(EdmPrimitiveTypeKind.Boolean, primitiveType.Kind); Assert.Equal("true", countable.DefaultValue); Assert.IsType <CsdlConstantExpression>(Assert.Single(countable.VocabularyAnnotations).Expression); // NonCountableProperties CsdlProperty nonCountable = complexType.StructuralProperties.FirstOrDefault(p => p.Name == "NonCountableProperties"); Assert.NotNull(nonCountable); CsdlExpressionTypeReference expressionType = Assert.IsType <CsdlExpressionTypeReference>(nonCountable.Type); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(Assert.IsType <CsdlCollectionType>(expressionType.TypeExpression).ElementType); Assert.Equal("Edm.PropertyPath", namedType.FullName); Assert.Null(nonCountable.DefaultValue); Assert.IsType <CsdlConstantExpression>(Assert.Single(nonCountable.VocabularyAnnotations).Expression); // NonCountableNavigationProperties CsdlProperty nonCountableNav = complexType.StructuralProperties.FirstOrDefault(p => p.Name == "NonCountableNavigationProperties"); Assert.NotNull(nonCountableNav); expressionType = Assert.IsType <CsdlExpressionTypeReference>(nonCountableNav.Type); namedType = Assert.IsType <CsdlNamedTypeReference>(Assert.IsType <CsdlCollectionType>(expressionType.TypeExpression).ElementType); Assert.Equal("Edm.NavigationPropertyPath", namedType.FullName); Assert.Null(nonCountableNav.DefaultValue); Assert.IsType <CsdlConstantExpression>(Assert.Single(nonCountableNav.VocabularyAnnotations).Expression); }
public void ParseCsdlOperationWithActionAndFunctionWorksAsExpected() { string json = @"""Approval"": [ { ""$Kind"": ""Action"", ""$IsBound"": true, ""$Parameter"": [ { ""$Name"": ""binding"", ""$Type"": ""self.Order"", ""$Nullable"": true } ] }, { ""$Kind"": ""Function"", ""$Parameter"": [ { ""$Name"": ""Rating"", ""$Type"": ""Edm.Decimal"", ""$Precision"": 4, ""$Scale"": 1 } ], ""$ReturnType"": { ""$Type"": ""self.Product"" } } ]"; IList <CsdlOperation> operations = ParseCsdlSchemaElement(json, SchemaJsonParser.TryParseCsdlOperationOverload); Assert.NotNull(operations); Assert.Equal(2, operations.Count); // #1 CsdlAction CsdlAction action = Assert.IsType <CsdlAction>(operations.First()); Assert.Equal("Approval", action.Name); Assert.True(action.IsBound); Assert.Null(action.EntitySetPath); CsdlOperationParameter parameter = Assert.Single(action.Parameters); Assert.Equal("binding", parameter.Name); Assert.False(parameter.IsOptional); Assert.Null(parameter.DefaultValue); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(parameter.Type); Assert.True(namedType.IsNullable); Assert.Equal("self.Order", namedType.FullName); Assert.Null(action.Return); // #2 CsdlFunction CsdlFunction function = Assert.IsType <CsdlFunction>(operations.Last()); Assert.Equal("Approval", function.Name); Assert.False(function.IsBound); Assert.Null(function.EntitySetPath); parameter = Assert.Single(function.Parameters); Assert.Equal("Rating", parameter.Name); Assert.False(parameter.IsOptional); Assert.Null(parameter.DefaultValue); CsdlDecimalTypeReference decimalType = Assert.IsType <CsdlDecimalTypeReference>(parameter.Type); Assert.False(decimalType.IsNullable); Assert.Equal(4, decimalType.Precision.Value); Assert.Equal(1, decimalType.Scale.Value); Assert.NotNull(function.Return); namedType = Assert.IsType <CsdlNamedTypeReference>(function.Return.ReturnType); Assert.False(namedType.IsNullable); Assert.Equal("self.Product", namedType.FullName); }
public void ParseCsdlOperationForFunctionWithMembersWorksAsExpected() { string json = @"""CreatedEntities"": [ { ""$Kind"": ""Function"", ""$Parameter"": [ { ""$Name"": ""before"", ""$Type"": ""Edm.DateTimeOffset"", ""$Nullable"": true, ""$Precision"": 10 }, { ""$Name"": ""after"", ""$Type"": ""Edm.DateTimeOffset"", ""$Precision"": 9 } ], ""$ReturnType"": { ""$Collection"": true, ""$Type"": ""Edm.EntityType"", ""$Nullable"": true }, ""$IsComposable"": true } ]"; IList <CsdlOperation> operations = ParseCsdlSchemaElement(json, SchemaJsonParser.TryParseCsdlOperationOverload); Assert.NotNull(operations); CsdlOperation operation = Assert.Single(operations); CsdlFunction function = Assert.IsType <CsdlFunction>(operation); Assert.Equal("CreatedEntities", function.Name); Assert.False(function.IsBound); Assert.True(function.IsComposable); Assert.Null(function.EntitySetPath); // Parameter Assert.Equal(2, function.Parameters.Count()); CsdlOperationParameter parameter = function.Parameters.First(c => c.Name == "before"); Assert.False(parameter.IsOptional); Assert.Null(parameter.DefaultValue); CsdlTemporalTypeReference temporalType = Assert.IsType <CsdlTemporalTypeReference>(parameter.Type); Assert.Equal(EdmPrimitiveTypeKind.DateTimeOffset, temporalType.Kind); Assert.True(temporalType.IsNullable); Assert.Equal(10, temporalType.Precision.Value); parameter = function.Parameters.First(c => c.Name == "after"); Assert.False(parameter.IsOptional); Assert.Null(parameter.DefaultValue); temporalType = Assert.IsType <CsdlTemporalTypeReference>(parameter.Type); Assert.Equal(EdmPrimitiveTypeKind.DateTimeOffset, temporalType.Kind); Assert.False(temporalType.IsNullable); Assert.Equal(9, temporalType.Precision.Value); // ReturnType Assert.NotNull(function.Return); CsdlExpressionTypeReference expTypeRef = Assert.IsType <CsdlExpressionTypeReference>(operation.Return.ReturnType); Assert.True(expTypeRef.IsNullable); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(Assert.IsType <CsdlCollectionType>(expTypeRef.TypeExpression).ElementType); Assert.True(namedType.IsNullable); // derived from collection Assert.Equal("Edm.EntityType", namedType.FullName); }
public void ParseCsdlEntityTypeWithMembersWorksAsExpected() { string json = @"""Supplier"": { ""$Kind"": ""EntityType"", ""$Key"": [ ""ID"" ], ""ID"": {}, ""Name"": { ""$Nullable"": true }, ""Address"": { ""$Type"": ""self.Address"" }, ""Concurrency"": { ""$Type"": ""Edm.Int32"" }, ""Products"": { ""$Kind"": ""NavigationProperty"", ""$Partner"": ""Supplier"", ""$Collection"": true, ""$Type"": ""self.Product"" } }"; CsdlEntityType entityType = ParseCsdlSchemaElement(json, SchemaJsonParser.ParseCsdlEntityType); Assert.NotNull(entityType); Assert.Equal("Supplier", entityType.Name); Assert.False(entityType.IsAbstract); Assert.False(entityType.IsOpen); Assert.Null(entityType.BaseTypeName); Assert.False(entityType.HasStream); CsdlPropertyReference propertyRef = Assert.Single(entityType.Key.Properties); Assert.Equal("ID", propertyRef.PropertyName); Assert.Equal(4, entityType.StructuralProperties.Count()); // ID CsdlProperty id = entityType.StructuralProperties.FirstOrDefault(p => p.Name == "ID"); Assert.NotNull(id); CsdlStringTypeReference stringType = Assert.IsType <CsdlStringTypeReference>(id.Type); Assert.False(stringType.IsUnbounded); Assert.Null(stringType.IsUnicode); Assert.Null(stringType.MaxLength); Assert.False(stringType.IsNullable); // Name CsdlProperty name = entityType.StructuralProperties.FirstOrDefault(p => p.Name == "Name"); Assert.NotNull(name); stringType = Assert.IsType <CsdlStringTypeReference>(name.Type); Assert.True(stringType.IsNullable); // Address CsdlProperty address = entityType.StructuralProperties.FirstOrDefault(p => p.Name == "Address"); Assert.NotNull(address); CsdlNamedTypeReference namedType = Assert.IsType <CsdlNamedTypeReference>(address.Type); Assert.Equal("self.Address", namedType.FullName); // Concurrency CsdlProperty concurrency = entityType.StructuralProperties.FirstOrDefault(p => p.Name == "Concurrency"); Assert.NotNull(concurrency); CsdlPrimitiveTypeReference primitiveType = Assert.IsType <CsdlPrimitiveTypeReference>(concurrency.Type); Assert.Equal(EdmPrimitiveTypeKind.Int32, primitiveType.Kind); Assert.False(primitiveType.IsNullable); // Products CsdlNavigationProperty products = Assert.Single(entityType.NavigationProperties); Assert.Equal("Products", products.Name); Assert.Equal("Collection(self.Product)", products.Type); Assert.Equal("Supplier", products.PartnerPath.Path); }
public CsdlSemanticsNamedTypeReference(CsdlSemanticsSchema schema, CsdlNamedTypeReference reference) : base(reference) { this.definitionCache = new Cache <CsdlSemanticsNamedTypeReference, IEdmType>(); this.schema = schema; this.reference = reference; }
internal static IEdmTypeReference WrapTypeReference(CsdlSemanticsSchema schema, CsdlTypeReference type) { CsdlNamedTypeReference reference = type as CsdlNamedTypeReference; if (reference != null) { CsdlPrimitiveTypeReference reference2 = reference as CsdlPrimitiveTypeReference; if (reference2 != null) { switch (reference2.Kind) { case EdmPrimitiveTypeKind.Binary: return(new CsdlSemanticsBinaryTypeReference(schema, (CsdlBinaryTypeReference)reference2)); case EdmPrimitiveTypeKind.Boolean: case EdmPrimitiveTypeKind.Byte: case EdmPrimitiveTypeKind.Double: case EdmPrimitiveTypeKind.Guid: case EdmPrimitiveTypeKind.Int16: case EdmPrimitiveTypeKind.Int32: case EdmPrimitiveTypeKind.Int64: case EdmPrimitiveTypeKind.SByte: case EdmPrimitiveTypeKind.Single: case EdmPrimitiveTypeKind.Stream: return(new CsdlSemanticsPrimitiveTypeReference(schema, reference2)); case EdmPrimitiveTypeKind.DateTime: case EdmPrimitiveTypeKind.DateTimeOffset: case EdmPrimitiveTypeKind.Time: return(new CsdlSemanticsTemporalTypeReference(schema, (CsdlTemporalTypeReference)reference2)); case EdmPrimitiveTypeKind.Decimal: return(new CsdlSemanticsDecimalTypeReference(schema, (CsdlDecimalTypeReference)reference2)); case EdmPrimitiveTypeKind.String: return(new CsdlSemanticsStringTypeReference(schema, (CsdlStringTypeReference)reference2)); case EdmPrimitiveTypeKind.Geography: case EdmPrimitiveTypeKind.GeographyPoint: case EdmPrimitiveTypeKind.GeographyLineString: case EdmPrimitiveTypeKind.GeographyPolygon: case EdmPrimitiveTypeKind.GeographyCollection: case EdmPrimitiveTypeKind.GeographyMultiPolygon: case EdmPrimitiveTypeKind.GeographyMultiLineString: case EdmPrimitiveTypeKind.GeographyMultiPoint: case EdmPrimitiveTypeKind.Geometry: case EdmPrimitiveTypeKind.GeometryPoint: case EdmPrimitiveTypeKind.GeometryLineString: case EdmPrimitiveTypeKind.GeometryPolygon: case EdmPrimitiveTypeKind.GeometryCollection: case EdmPrimitiveTypeKind.GeometryMultiPolygon: case EdmPrimitiveTypeKind.GeometryMultiLineString: case EdmPrimitiveTypeKind.GeometryMultiPoint: return(new CsdlSemanticsSpatialTypeReference(schema, (CsdlSpatialTypeReference)reference2)); } } return(new CsdlSemanticsNamedTypeReference(schema, reference)); } CsdlExpressionTypeReference expressionUsage = type as CsdlExpressionTypeReference; if (expressionUsage != null) { CsdlRowType typeExpression = expressionUsage.TypeExpression as CsdlRowType; if (typeExpression != null) { return(new CsdlSemanticsRowTypeExpression(expressionUsage, new CsdlSemanticsRowTypeDefinition(schema, typeExpression))); } CsdlCollectionType collection = expressionUsage.TypeExpression as CsdlCollectionType; if (collection != null) { return(new CsdlSemanticsCollectionTypeExpression(expressionUsage, new CsdlSemanticsCollectionTypeDefinition(schema, collection))); } CsdlEntityReferenceType entityTypeReference = expressionUsage.TypeExpression as CsdlEntityReferenceType; if (entityTypeReference != null) { return(new CsdlSemanticsEntityReferenceTypeExpression(expressionUsage, new CsdlSemanticsEntityReferenceTypeDefinition(schema, entityTypeReference))); } } return(null); }