/// <summary> /// Returns the structural property for the given payload element (only for properties). /// </summary> /// <param name="expectedTypeAnnotation">The expected type annotation.</param> /// <param name="model">The model to get the structural property from.</param> /// <returns>The expected structural property for the specified payload element.</returns> private static IEdmStructuralProperty GetExpectedStructuralProperty(ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, IEdmModel model) { ExceptionUtilities.Assert(model != null, "model != null"); if (expectedTypeAnnotation != null) { if (expectedTypeAnnotation.EdmProperty != null) { return(expectedTypeAnnotation.EdmProperty as IEdmStructuralProperty); } MemberProperty expectedStructuralProperty = expectedTypeAnnotation.MemberProperty; if (expectedStructuralProperty != null) { NamedStructuralType expectedOwningType = expectedTypeAnnotation.OwningType; ExceptionUtilities.Assert(expectedOwningType != null, "Need an owning type if a structural property is specified."); IEdmStructuredType owningType = model.FindType(expectedOwningType.FullName) as IEdmStructuredType; ExceptionUtilities.Assert(owningType != null, "Did not find expected structured type in the model."); IEdmStructuralProperty structuralProperty = owningType.FindProperty(expectedStructuralProperty.Name) as IEdmStructuralProperty; ExceptionUtilities.Assert(structuralProperty != null, "Did not find expected structural property in the model."); return(structuralProperty); } } return(null); }
/// <summary> /// Returns the function import for a parameters payload. /// </summary> /// <param name="expectedTypeAnnotation">The expected type annotation.</param> /// <param name="model">The model to get the function import from.</param> /// <returns>Returns the function import for a parameters payload.</returns> private static IEdmOperationImport GetExpectedFunctionImport(ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, IEdmModel model) { ExceptionUtilities.Assert(model != null, "model != null"); if (expectedTypeAnnotation != null) { if (expectedTypeAnnotation.ProductFunctionImport != null) { return(expectedTypeAnnotation.ProductFunctionImport); } FunctionImport functionImport = expectedTypeAnnotation.FunctionImport; if (functionImport != null) { var container = model.FindEntityContainer(functionImport.Container.FullName); var functionImports = container.FindOperationImports(functionImport.Name); if (functionImports != null && functionImports.Any()) { // Note that we don't support overload for Actions. Single() will throw if the model is invalid. return(functionImports.Single()); } } } return(null); }
/// <summary> /// Returns the entity set for the given payload element (only for entries and feeds). /// </summary> /// <param name="expectedTypeAnnotation">The expected type annotation.</param> /// <param name="model">The model to get the type from.</param> /// <param name="payloadElement">The payload element to get the expected type for.</param> /// <returns>The expected type for the specified payload element.</returns> private static IEdmEntitySet GetExpectedEntitySet(ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, IEdmModel model, ODataPayloadElement payloadElement) { ExceptionUtilities.Assert(model != null, "model != null"); ExceptionUtilities.Assert(payloadElement != null, "payloadElement != null"); if (payloadElement.GetAnnotation <IgnoreEntitySetAnnotation>() != null) { // Entity set information is explicitly ignored return(null); } if (expectedTypeAnnotation != null) { if (expectedTypeAnnotation.EdmEntitySet != null) { return(expectedTypeAnnotation.EdmEntitySet); } EntitySet entitySet = expectedTypeAnnotation.EntitySet; if (entitySet != null) { return(model.EntityContainersAcrossModels().Select(m => m.FindEntitySet(entitySet.Name)).FirstOrDefault(s => s != null)); } } EntityModelTypeAnnotation typeAnnotation = payloadElement.GetAnnotation <EntityModelTypeAnnotation>(); if (typeAnnotation != null) { var edmEntityType = typeAnnotation.EdmModelType; return(model.EntityContainersAcrossModels().First().EntitySets().SingleOrDefault(es => es.EntityType().FullName() == edmEntityType.FullName())); } return(null); }
/// <summary> /// Returns the expected type for the given payload element. /// </summary> /// <param name="expectedTypeAnnotation">The expected type annotation.</param> /// <param name="model">The model to get the type from.</param> /// <returns>The expected type for the specified payload element.</returns> private static IEdmTypeReference GetExpectedType(ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, IEdmModel model) { if (expectedTypeAnnotation != null) { if (expectedTypeAnnotation.EdmExpectedType != null) { return(expectedTypeAnnotation.EdmExpectedType); } if (expectedTypeAnnotation.ExpectedType != null) { DataType expectedDataType = expectedTypeAnnotation.ExpectedType; return(EdmModelUtils.ResolveEntityModelSchemaType(model, expectedDataType)); } } return(null); }
private void AddExpectedFunctionImportToCollection(ODataPayloadElementCollection collection) { var expectedTypeAnnotation = collection.GetAnnotation <ExpectedTypeODataPayloadElementAnnotation>(); if (expectedTypeAnnotation == null) { expectedTypeAnnotation = new ExpectedTypeODataPayloadElementAnnotation(); collection.Add(expectedTypeAnnotation); } if (expectedTypeAnnotation.ProductFunctionImport == null) { var typeAnnotation = collection.GetAnnotation <EntityModelTypeAnnotation>(); var collectionType = typeAnnotation.EdmModelType; if (this.testDescriptor.PayloadEdmModel != null) { EdmModel model = this.testDescriptor.PayloadEdmModel as EdmModel; EdmEntityContainer container = model.EntityContainer as EdmEntityContainer; var functionImport = container.OperationImports().FirstOrDefault(f => { return(f.Operation.ReturnType != null && f.Operation.ReturnType == collectionType); }); if (functionImport == null) { functionImport = container.OperationImports().FirstOrDefault(f => { return(f.Operation.ReturnType != null && f.Operation.ReturnType.IsCollection()); }); if (functionImport == null) { var collectionNameAnnotation = collection.GetAnnotation <CollectionNameAnnotation>(); container.AddFunctionAndFunctionImport(model, collectionNameAnnotation == null ? "NewFunctionImport" : collectionNameAnnotation.Name, collectionType); this.testDescriptor.ResetCachedModel(); } } expectedTypeAnnotation.ProductFunctionImport = functionImport as EdmOperationImport; } } }
/// <summary> /// Adds or modifies a property's ExpectedTypeODataPayloadElementAnnotation, to aid generation of the context uri. /// </summary> /// <param name="property">The property to annotate.</param> /// <param name="propertyValueType">The type of the property's value.</param> /// <param name="matchesProperty">Delegate for matching the property instance to a MemberProperty.</param> /// <remarks> /// If the method cannot resolve the parent type of the property, one will be created and added to the test descriptor's /// PayloadModel. The descriptor's cached model will be reset. /// </remarks> private void AddExpectedTypeToProperty(PropertyInstance property, IEdmTypeReference propertyValueType, Func <IEdmProperty, bool> matchesProperty) { if (property.Annotations.OfType <JsonLightContextUriAnnotation>().Any()) { return; } var typeAnnotation = property.Annotations.OfType <ExpectedTypeODataPayloadElementAnnotation>().SingleOrDefault(); if (typeAnnotation == null || (typeAnnotation.MemberProperty == null && string.IsNullOrEmpty(typeAnnotation.OpenMemberPropertyName))) { ExpectedTypeODataPayloadElementAnnotation annotation = typeAnnotation ?? new ExpectedTypeODataPayloadElementAnnotation(); IEdmModel model = this.testDescriptor.PayloadEdmModel; var entityType = model.EntityTypes().SingleOrDefault(t => t.Properties().Any(matchesProperty)); if (entityType != null) { annotation.EdmEntitySet = FindEntitySet(model, entityType); annotation.EdmOwningType = entityType; annotation.EdmProperty = entityType.Properties().FirstOrDefault(matchesProperty); } else { var complexType = model.SchemaElements.OfType <IEdmComplexType>().SingleOrDefault(t => t.Properties().Any(matchesProperty)); if (complexType != null) { var complexProperty = complexType.Properties().Single(p => p.Name == property.Name); annotation.EdmOwningType = complexType; annotation.EdmProperty = complexProperty; annotation.EdmExpectedType = complexProperty.Type; } else { // Add new entity type to the model and use that IEdmTypeReference propertyType = annotation.EdmExpectedType ?? propertyValueType; EdmEntityType newEntityType = model.FindDeclaredType("TestModel.NewType") as EdmEntityType; IEdmEntitySet newEntitySet = null; IEdmProperty newProperty = null; string newPorpertyName = property.Name ?? propertyType.FullName() ?? "EmptyName"; if (newEntityType == null) { newEntityType = new EdmEntityType("TestModel", "NewType"); newProperty = newEntityType.AddStructuralProperty(newPorpertyName, propertyType); ((EdmModel)model).AddElement(newEntityType); var container = model.EntityContainersAcrossModels().Single() as EdmEntityContainer; newEntitySet = container.AddEntitySet("NewTypes", newEntityType); } else { newProperty = newEntityType.AddStructuralProperty(newPorpertyName, propertyType); newEntitySet = FindEntitySet(model, newEntityType); } annotation.EdmEntitySet = newEntitySet; annotation.EdmOwningType = newEntityType; annotation.EdmProperty = newProperty; annotation.EdmExpectedType = propertyType; this.testDescriptor.PayloadEdmModel = model; this.testDescriptor.ResetCachedModel(); } } property.SetAnnotation(annotation); } }
/// <summary> /// Builds a context URI from the expected type annotation. /// </summary> /// <param name="payloadElementKind">The payload element kind to build the context URI for.</param> /// <param name="metadataDocumentUri">The metadata document URI.</param> /// <param name="expectedTypeAnnotation">The expected type annotation.</param> /// <returns>The constructed context URI.</returns> public static string BuildContextUri(ODataPayloadElementType payloadElementKind, string metadataDocumentUri, ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation, string projectionString = null) { ExceptionUtilities.CheckArgumentNotNull(metadataDocumentUri, "metadataDocumentUri"); ExceptionUtilities.CheckArgumentNotNull(expectedTypeAnnotation, "expectedTypeAnnotation"); StringBuilder builder = new StringBuilder(metadataDocumentUri); switch (payloadElementKind) { // Entry payload case ODataPayloadElementType.EntityInstance: { EdmEntitySet entitySet = (EdmEntitySet)expectedTypeAnnotation.EdmEntitySet; ExceptionUtilities.Assert(entitySet != null, "Entity set is required for entry payloads."); builder.Append('#'); AppendEntityContainerElement(builder, entitySet.Container, entitySet.Name); AppendTypeCastIfNeeded(builder, entitySet, expectedTypeAnnotation.EdmExpectedType.Definition); builder.Append(projectionString); builder.Append("/$entity"); break; } // Feed payload case ODataPayloadElementType.EntitySetInstance: { EdmEntitySet entitySet = (EdmEntitySet)expectedTypeAnnotation.EdmEntitySet; ExceptionUtilities.Assert(entitySet != null, "Entity set is required for feed payloads."); builder.Append('#'); AppendEntityContainerElement(builder, entitySet.Container, entitySet.Name); AppendTypeCastIfNeeded(builder, entitySet, expectedTypeAnnotation.EdmExpectedType.Definition); builder.Append(projectionString); break; } // Property payload case ODataPayloadElementType.PrimitiveProperty: // fall through case ODataPayloadElementType.PrimitiveMultiValueProperty: // fall through case ODataPayloadElementType.ComplexMultiValueProperty: // fall through case ODataPayloadElementType.ComplexProperty: // fall through case ODataPayloadElementType.NullPropertyInstance: // Collection payload case ODataPayloadElementType.EmptyCollectionProperty: // fall through case ODataPayloadElementType.ComplexInstanceCollection: // fall through case ODataPayloadElementType.PrimitiveCollection: builder.Append('#'); // NOTE: property payloads can be produced by regular properties as well as function imports IEdmTypeReference edmExpectedType = null; if (expectedTypeAnnotation.EdmProperty != null) { edmExpectedType = expectedTypeAnnotation.EdmProperty.Type; } else if (expectedTypeAnnotation.ProductFunctionImport != null) { edmExpectedType = expectedTypeAnnotation.ProductFunctionImport.Operation.ReturnType; } else if (expectedTypeAnnotation.EdmExpectedType != null) { edmExpectedType = expectedTypeAnnotation.EdmExpectedType; } if (edmExpectedType == null) { if (expectedTypeAnnotation.EdmExpectedType != null) { AppendTypeName(builder, expectedTypeAnnotation.EdmExpectedType.Definition); } else if (expectedTypeAnnotation.ProductFunctionImport != null) { AppendTypeName(builder, expectedTypeAnnotation.ProductFunctionImport.Operation.ReturnType.Definition); } } else { AppendTypeName(builder, edmExpectedType.Definition); } break; // Entity reference link payload case ODataPayloadElementType.DeferredLink: case ODataPayloadElementType.LinkCollection: { IEdmEntitySet entitySet = expectedTypeAnnotation.EdmEntitySet; EdmNavigationProperty navigationProperty = expectedTypeAnnotation.EdmNavigationProperty as EdmNavigationProperty; IEdmEntityType entityType = navigationProperty.DeclaringEntityType; ExceptionUtilities.Assert(entitySet != null, "entitySet is required for entity reference link payloads."); ExceptionUtilities.Assert(navigationProperty != null, "Navigation property is required for entity reference link payloads."); builder.Append('#'); if (payloadElementKind == ODataPayloadElementType.DeferredLink) { builder.Append("$ref"); } else if (payloadElementKind == ODataPayloadElementType.LinkCollection) { builder.Append("Collection($ref)"); } break; } // Service document payload case ODataPayloadElementType.ServiceDocumentInstance: // fall through case ODataPayloadElementType.WorkspaceInstance: // NOTE: the builder already contains the metadata document URI. break; default: return(null); } return(builder.ToString()); }
/// <summary> /// Gets the context URI for the specified ODataPayloadElement. /// </summary> /// <param name="payloadElement">The annotated payload element to get the context URI for.</param> /// <returns>The context URI from the annotated payload element or null if no context URI annotation exists.</returns> /// <remarks>If not context URI annotation is found on the <paramref name="payloadElement"/>, this /// method will try to compute the context URI from the expected type annotation. If successful, /// it will cache the computed context URI as annotation on the payload element.</remarks> public static string ContextUri(this ODataPayloadElement payloadElement) { ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement"); JsonLightContextUriAnnotation contextUriAnnotation = (JsonLightContextUriAnnotation)payloadElement.GetAnnotation(typeof(JsonLightContextUriAnnotation)); string contextUri = null; bool cacheContextUri = false; // If an explicit context URI exists, return it if (contextUriAnnotation != null) { contextUri = contextUriAnnotation.ContextUri; } else { // Otherwise construct a context URI from the expected type annotation ExpectedTypeODataPayloadElementAnnotation expectedTypeAnnotation = (ExpectedTypeODataPayloadElementAnnotation)payloadElement.GetAnnotation(typeof(ExpectedTypeODataPayloadElementAnnotation)); if (expectedTypeAnnotation != null) { // Construct a context URI from the exptected type annotation JsonLightMetadataDocumentUriAnnotation metadataDocumentUriAnnotation = (JsonLightMetadataDocumentUriAnnotation)payloadElement.GetAnnotation(typeof(JsonLightMetadataDocumentUriAnnotation)); string metadataDocumentUri = metadataDocumentUriAnnotation == null ? JsonLightConstants.DefaultMetadataDocumentUri.AbsoluteUri : metadataDocumentUriAnnotation.MetadataDocumentUri; string projectionString = null; JsonLightContextUriProjectionAnnotation contextUriProjectionAnnotation = (JsonLightContextUriProjectionAnnotation)payloadElement.GetAnnotation(typeof(JsonLightContextUriProjectionAnnotation)); if (contextUriProjectionAnnotation != null) { // If we have a context URI projection, apply it to the context URI if the context URI does not already have one. projectionString = contextUriProjectionAnnotation.ContextUriProjection; Regex contextUriSelectExpandPattern = new Regex(@"(?:(?<!#Collection))\(.*\)"); // A 'null' projection string means that all properties should be projected. if (projectionString != null) { bool hasProjection = contextUriSelectExpandPattern.IsMatch(projectionString); if (!hasProjection) { // Inject the projection string into the context URI projectionString = JsonLightConstants.ContextUriProjectionStart + projectionString + JsonLightConstants.ContextUriProjectionEnd; } } } contextUri = BuildContextUri(payloadElement.ElementType, metadataDocumentUri, expectedTypeAnnotation, projectionString); cacheContextUri = true; } } // Cache the computed context URI on the payload element (non-comparable annotation) if (cacheContextUri) { payloadElement.WithContextUri(contextUri); payloadElement.RemoveAnnotations(typeof(JsonLightContextUriProjectionAnnotation)); } return(contextUri); }