public void GetTemplatesWorksForODataPathWithDollarRefOnSingleNavigation() { // Arrange EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); var entitySet = container.AddEntitySet("Customers", customer); var navigation = customer.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { TargetMultiplicity = EdmMultiplicity.One, Name = "SubCustomer", Target = customer }); ODataPathTemplate template = new ODataPathTemplate( new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(customer, entitySet), new NavigationLinkSegmentTemplate(navigation, entitySet)); // Act IEnumerable <(string, string)> actual = template.GetTemplates(); // Assert Assert.Equal(2, actual.Count()); Assert.Equal(new[] { "Customers({key})/SubCustomer/$ref", "Customers/{key}/SubCustomer/$ref" }, actual.Select(a => a.Item1)); }
internal static bool ProcessNonNavigationProperty(string httpMethod, ODataControllerActionContext context, ActionModel action, IEdmNavigationSource navigationSource, IEdmEntityType entityType, IEdmStructuredType castType) { // Action parameter should have a (string navigationProperty) parameter if (!action.HasParameter <string>("navigationProperty")) { return(false); } // Let's only handle single-key convention, for composite key, use attribute routing or non-generic navigation. bool hasRelatedKey = action.Parameters.Any(p => p.Name == "relatedKey"); // case sensitive? bool hasRelatedId = action.Parameters.Any(p => p.Name == "relatedId"); IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (entityType != castType) { segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource)); } if (hasRelatedKey) { segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource) { RelatedKey = "relatedKey" }); } else if (hasRelatedId) { segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource) { RelatedKey = "relatedId" }); } else { segments.Add(new NavigationLinkTemplateSegmentTemplate(entityType, navigationSource)); } ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions); return(true); }
public void TryTranslateNavigationLinkSegmentTemplate_ReturnsODataNavigationSegment() { // Arrange EdmModel model = new EdmModel(); model.AddElement(_employee); NavigationLinkSegmentTemplate linkSegment = new NavigationLinkSegmentTemplate(_navigation, null); RouteValueDictionary routeValueDictionary = new RouteValueDictionary(new { id = "42" }); ODataTemplateTranslateContext context = new ODataTemplateTranslateContext { RouteValues = routeValueDictionary, Model = model }; // Without key segment // Act & Assert bool ok = linkSegment.TryTranslate(context); Assert.True(ok); ODataPathSegment actual = Assert.Single(context.Segments); NavigationPropertyLinkSegment navLinkSegment = Assert.IsType <NavigationPropertyLinkSegment>(actual); Assert.Same(_navigation, navLinkSegment.NavigationProperty); Assert.Null(navLinkSegment.NavigationSource); // With Key segment // Act & Assert context = new ODataTemplateTranslateContext { RouteValues = routeValueDictionary, Model = model }; linkSegment.Key = KeySegmentTemplate.CreateKeySegment(_employee, null, "id"); ok = linkSegment.TryTranslate(context); Assert.True(ok); Assert.Collection(context.Segments, e => { NavigationPropertyLinkSegment navLinkSegment = Assert.IsType <NavigationPropertyLinkSegment>(e); Assert.Same(_navigation, navLinkSegment.NavigationProperty); Assert.Null(navLinkSegment.NavigationSource); }, e => { KeySegment keySegment = Assert.IsType <KeySegment>(e); KeyValuePair <string, object> key = Assert.Single(keySegment.Keys); Assert.Equal("Id", key.Key); Assert.Equal(42, key.Value); }); }
private static void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action, IEdmNavigationSource navigationSource, IEdmStructuralProperty edmProperty, IEdmType cast, IEdmEntityType declaringType, bool dollarValue, bool dollarCount) { IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType(); IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (entitySet != null) { segments.Add(new EntitySetSegmentTemplate(entitySet)); segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource)); } else { segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton)); } if (declaringType != null && declaringType != entityType) { segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource)); } segments.Add(new PropertySegmentTemplate(edmProperty)); if (cast != null) { if (edmProperty.Type.IsCollection()) { cast = new EdmCollectionType(cast.ToEdmTypeReference(edmProperty.Type.IsNullable)); } // TODO: maybe create the collection type for the collection???? segments.Add(new CastSegmentTemplate(cast, edmProperty.Type.Definition, navigationSource)); } if (dollarValue) { segments.Add(new ValueSegmentTemplate(edmProperty.Type.Definition)); } if (dollarCount) { segments.Add(CountSegmentTemplate.Instance); } ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod.NormalizeHttpMethod(), context.Prefix, context.Model, template, context.Options?.RouteOptions); }
public void CreateKeySegmentKeySegmentTemplate_ReturnsKeySegmentTemplate() { // Arrange KeySegmentTemplate template = KeySegmentTemplate.CreateKeySegment(_customerType, _customers, "id"); // Assert Assert.NotNull(template); Assert.Equal(1, template.Count); KeyValuePair <string, string> keyMapping = Assert.Single(template.KeyMappings); Assert.Equal("customerId", keyMapping.Key); Assert.Equal("id", keyMapping.Value); }
private void AddSelector(string httpMethod, ODataControllerActionContext context, ActionModel action, IEdmNavigationSource navigationSource, string declared, IEdmEntityType declaringEntityType, IEdmNavigationProperty navigationProperty, bool hasKey, bool dollarCount) { IEdmEntitySet entitySet = navigationSource as IEdmEntitySet; IEdmEntityType entityType = navigationSource.EntityType(); // Starts the routing template IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (entitySet != null) { segments.Add(new EntitySetSegmentTemplate(entitySet)); } else { segments.Add(new SingletonSegmentTemplate(navigationSource as IEdmSingleton)); } if (hasKey) { segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource)); } if (declared != null) { // It should be always single type if (entityType != declaringEntityType) { segments.Add(new CastSegmentTemplate(declaringEntityType, entityType, navigationSource)); } } IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); segments.Add(new NavigationSegmentTemplate(navigationProperty, targetNavigationSource)); if (dollarCount) { segments.Add(CountSegmentTemplate.Instance); } ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod.NormalizeHttpMethod(), context.Prefix, context.Model, template, context.RouteOptions); Log.AddedODataSelector(_logger, action, template); }
public void CreateKeySegmentKeySegmentTemplate_ReturnsKeySegmentTemplate_CompositeKey() { // Arrange EdmEntityType customerType = new EdmEntityType("NS", "Customer"); EdmStructuralProperty firstProperty = customerType.AddStructuralProperty("firstName", EdmPrimitiveTypeKind.String); EdmStructuralProperty lastProperty = customerType.AddStructuralProperty("lastName", EdmPrimitiveTypeKind.String); customerType.AddKeys(firstProperty, lastProperty); // Act KeySegmentTemplate template = KeySegmentTemplate.CreateKeySegment(customerType, null); // Assert Assert.NotNull(template); Assert.Equal(2, template.Count); }
public void GetTemplatesWorksForPathWithTypeCastAndFunction() { // Arrange EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); // VipCustomer EdmEntityType vipCustomer = new EdmEntityType("NS", "VipCustomer", customer); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); var entitySet = container.AddEntitySet("Customers", customer); // function with optional parameters EdmFunction getSalaray = new EdmFunction("NS", "GetWholeSalary", IntType, isBound: true, entitySetPathExpression: null, isComposable: false); getSalaray.AddParameter("entityset", new EdmEntityTypeReference(vipCustomer, false)); getSalaray.AddParameter("salary", IntType); getSalaray.AddOptionalParameter("minSalary", IntType); getSalaray.AddOptionalParameter("maxSalary", IntType, "129"); ODataPathTemplate template = new ODataPathTemplate( new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(customer, entitySet), new CastSegmentTemplate(vipCustomer, customer, entitySet), new FunctionSegmentTemplate(getSalaray, null)); // Act IEnumerable <(string, string)> actual = template.GetTemplates(); Assert.Equal(4, actual.Count()); Assert.Equal(new[] { "Customers({key})/NS.VipCustomer/NS.GetWholeSalary({salary;minSalary;maxSalary})", "Customers({key})/NS.VipCustomer/GetWholeSalary({salary;minSalary;maxSalary})", "Customers/{key}/NS.VipCustomer/NS.GetWholeSalary({salary;minSalary;maxSalary})", "Customers/{key}/NS.VipCustomer/GetWholeSalary({salary;minSalary;maxSalary})", }, actual.Select(a => a.Item1)); Assert.Equal(new[] { "Customers({key})/NS.VipCustomer/NS.GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})", "Customers({key})/NS.VipCustomer/GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})", "Customers/{key}/NS.VipCustomer/NS.GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})", "Customers/{key}/NS.VipCustomer/GetWholeSalary(salary={salary},minSalary={minSalary},maxSalary={maxSalary})", }, actual.Select(a => a.Item2)); }
public void GetTemplatesNavigationLinkSegmentTemplate_ReturnsTemplates() { // Arrange NavigationLinkSegmentTemplate linkSegment = new NavigationLinkSegmentTemplate(_navigation, null); // Act & Assert IEnumerable <string> templates = linkSegment.GetTemplates(); string template = Assert.Single(templates); Assert.Equal("/DirectReports/$ref", template); // Act & Assert linkSegment.Key = KeySegmentTemplate.CreateKeySegment(_employee, null); templates = linkSegment.GetTemplates(); Assert.Collection(templates, e => Assert.Equal("/DirectReports({key})/$ref", e), e => Assert.Equal("/DirectReports/{key}/$ref", e)); }
public void GetTemplatesWorksForBasicPath() { // Arrange EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); var entitySet = container.AddEntitySet("Customers", customer); ODataPathTemplate template = new ODataPathTemplate( new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(customer, entitySet)); // Act IEnumerable <(string, string)> actual = template.GetTemplates(); // Assert Assert.Equal(2, actual.Count()); Assert.Equal(new[] { "Customers({key})", "Customers/{key}" }, actual.Select(a => a.Item1)); }
public void GetTemplatesWorksForODataPathWithDollarRefOnCollectionNavigation() { // Arrange EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); var entitySet = container.AddEntitySet("Customers", customer); var navigation = customer.AddUnidirectionalNavigation(new EdmNavigationPropertyInfo { TargetMultiplicity = EdmMultiplicity.Many, Name = "SubCustomers", Target = customer }); KeyValuePair <string, object>[] keys = new KeyValuePair <string, object>[] { new KeyValuePair <string, object>("Id", "{nextKey}") }; KeySegment keySegment = new KeySegment(keys, customer, entitySet); ODataPathTemplate template = new ODataPathTemplate( new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(customer, entitySet), new NavigationLinkSegmentTemplate(navigation, entitySet) { Key = new KeySegmentTemplate(keySegment) }); // Act IEnumerable <string> actual = template.GetTemplates(); // Assert Assert.Equal(4, actual.Count()); Assert.Equal(new[] { "Customers({key})/SubCustomers({nextKey})/$ref", "Customers({key})/SubCustomers/{nextKey}/$ref", "Customers/{key}/SubCustomers({nextKey})/$ref", "Customers/{key}/SubCustomers/{nextKey}/$ref" }, actual); }
public void TranslateODataPathTemplate_ToODataPath() { // Assert EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("CustomerId", EdmPrimitiveTypeKind.Int32)); EdmEntityContainer container = new EdmEntityContainer("NS", "Default"); var entitySet = container.AddEntitySet("Customers", customer); EdmModel model = new EdmModel(); model.AddElement(customer); model.AddElement(container); ODataPathTemplate template = new ODataPathTemplate( new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(customer, entitySet)); DefaultODataTemplateTranslator translator = new DefaultODataTemplateTranslator(); ODataTemplateTranslateContext context = new ODataTemplateTranslateContext { RouteValues = new RouteValueDictionary(new { key = "42" }), Model = model }; // Act ODataPath path = translator.Translate(template, context); // Assert Assert.NotNull(path); Assert.Equal(2, path.Count); EntitySetSegment entitySetSegment = Assert.IsType <EntitySetSegment>(path.FirstSegment); Assert.Equal("Customers", entitySetSegment.EntitySet.Name); KeySegment keySegment = Assert.IsType <KeySegment>(path.LastSegment); KeyValuePair <string, object> key = Assert.Single(keySegment.Keys); Assert.Equal("CustomerId", key.Key); Assert.Equal(42, key.Value); }
private static void AddSelector(IEdmEntitySet entitySet, IEdmEntityType entityType, IEdmStructuredType castType, string prefix, IEdmModel model, ActionModel action, string httpMethod) { IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate> { new EntitySetSegmentTemplate(entitySet), KeySegmentTemplate.CreateKeySegment(entityType, entitySet) }; // If we have the type cast if (castType != null) { if (castType == entityType) { // If cast type is the entity type of the entity set. // we support two templates // ~/Customers({key}) action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments)); // ~/Customers({key})/Ns.Customer segments.Add(new CastSegmentTemplate(castType, entityType, entitySet)); action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments)); } else { // ~/Customers({key})/Ns.VipCustomer segments.Add(new CastSegmentTemplate(castType, entityType, entitySet)); action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments)); } } else { // ~/Customers({key}) action.AddSelector(httpMethod, prefix, model, new ODataPathTemplate(segments)); } }
public void CreateKeySegmentKeySegmentTemplate_ThrowsArgumentNull_EntityType() { // Arrange & Act & Assert ExceptionAssert.ThrowsArgumentNull(() => KeySegmentTemplate.CreateKeySegment(null, null), "entityType"); }
/// <summary> /// Add the template to the action /// </summary> /// <param name="context">The context.</param> /// <param name="edmOperation">The Edm operation.</param> /// <param name="hasKeyParameter">Has key parameter or not.</param> /// <param name="entityType">The entity type.</param> /// <param name="navigationSource">The navigation source.</param> /// <param name="castType">The type cast.</param> protected static void AddSelector(ODataControllerActionContext context, IEdmOperation edmOperation, bool hasKeyParameter, IEdmEntityType entityType, IEdmNavigationSource navigationSource, IEdmEntityType castType) { Contract.Assert(context != null); Contract.Assert(entityType != null); Contract.Assert(navigationSource != null); Contract.Assert(edmOperation != null); // Now, let's add the selector model. IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); if (hasKeyParameter) { segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, navigationSource)); } } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (castType != null) { if (context.Singleton != null || !hasKeyParameter) { segments.Add(new CastSegmentTemplate(castType, entityType, navigationSource)); } else { segments.Add(new CastSegmentTemplate(new EdmCollectionType(castType.ToEdmTypeReference(false)), new EdmCollectionType(entityType.ToEdmTypeReference(false)), navigationSource)); } } IEdmNavigationSource targetset = null; if (edmOperation.ReturnType != null) { targetset = edmOperation.GetTargetEntitySet(navigationSource, context.Model); } string httpMethod; if (edmOperation.IsAction()) { segments.Add(new ActionSegmentTemplate((IEdmAction)edmOperation, targetset)); httpMethod = "post"; } else { IDictionary <string, string> required = GetRequiredFunctionParamters(edmOperation, context.Action); segments.Add(new FunctionSegmentTemplate(required, (IEdmFunction)edmOperation, targetset)); httpMethod = "get"; } ODataPathTemplate template = new ODataPathTemplate(segments); context.Action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions); }
/// <inheritdoc /> public bool AppliesToAction(ODataControllerActionContext context) { if (context == null) { throw Error.ArgumentNull(nameof(context)); } Debug.Assert(context.Action != null); ActionModel action = context.Action; string actionMethodName = action.ActionName; // Need to refactor the following // for example: CreateRef( with the navigation property parameter) should for all navigation properties // CreateRefToOrdersFromCustomer, CreateRefToOrders, CreateRef. string method = SplitRefActionName(actionMethodName, out string httpMethod, out string property, out string declaring); if (method == null) { return(false); } IEdmNavigationSource navigationSource = context.NavigationSource; IEdmEntityType entityType = context.EntityType; // For entity set, we should have the key parameter // For Singleton, we should not have the key parameter bool hasODataKeyParameter = action.HasODataKeyParameter(entityType); if ((context.EntitySet != null && !hasODataKeyParameter) || (context.Singleton != null && hasODataKeyParameter)) { return(false); } // Find the navigation property declaring type IEdmStructuredType declaringType = entityType; if (declaring != null) { declaringType = entityType.FindTypeInInheritance(context.Model, declaring); if (declaringType == null) { return(false); } } // Process the generic scenario if (property == null) { return(ProcessNonNavigationProperty(httpMethod, context, action, navigationSource, entityType, declaringType)); } // Find the navigation property if have IEdmNavigationProperty navigationProperty = null; if (property != null) { navigationProperty = declaringType.DeclaredNavigationProperties().FirstOrDefault(p => p.Name == property); } if (navigationProperty == null) { return(false); } IList <ODataSegmentTemplate> segments = new List <ODataSegmentTemplate>(); if (context.EntitySet != null) { segments.Add(new EntitySetSegmentTemplate(context.EntitySet)); segments.Add(KeySegmentTemplate.CreateKeySegment(entityType, context.EntitySet)); } else { segments.Add(new SingletonSegmentTemplate(context.Singleton)); } if (entityType != declaringType) { segments.Add(new CastSegmentTemplate(declaringType, entityType, navigationSource)); } IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty, segments, out _); NavigationLinkSegmentTemplate linkTemplate = new NavigationLinkSegmentTemplate(navigationProperty, targetNavigationSource); IEdmEntityType navigationPropertyType = navigationProperty.Type.GetElementTypeOrSelf().AsEntity().EntityDefinition(); bool hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedKey"); if (hasNavigationPropertyKeyParameter) { linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedKey"); } else { hasNavigationPropertyKeyParameter = action.HasODataKeyParameter(navigationPropertyType, "relatedId"); if (hasNavigationPropertyKeyParameter) { linkTemplate.Key = KeySegmentTemplate.CreateKeySegment(navigationPropertyType, targetNavigationSource, "relatedId"); } } segments.Add(linkTemplate); ODataPathTemplate template = new ODataPathTemplate(segments); action.AddSelector(httpMethod, context.Prefix, context.Model, template, context.Options?.RouteOptions); // processed return(true); }