public static string TranslateKeyValueToString(this KeySegment segment) { Contract.Assert(segment != null); IEdmEntityType entityType = segment.EdmType as IEdmEntityType; Contract.Assert(entityType != null); var keys = segment.Keys.ToList(); if (keys.Count < 2) { var keyValue = keys.First(); bool isDeclaredKey = entityType.Key().Any(k => k.Name == keyValue.Key); // alternate keys are always using the "key=value" if (isDeclaredKey) { return(String.Join( ",", keys.Select(keyValuePair => TranslateKeySegmentValue(keyValuePair.Value)).ToArray())); } } return(String.Join( ",", keys.Select(keyValuePair => (keyValuePair.Key + "=" + TranslateKeySegmentValue(keyValuePair.Value))).ToArray())); }
/// <summary> ///A test for GetValue ///</summary> void GetValueTestHelper <E, T>(E e, T tail) where E : class where T : ITrashable { KeySegment <E, T> target = new KeySegment <E, T>() { _elementReference = new WeakKey <E> { _elementReference = new WeakReference(e) }, _tail = tail } ; E value = null; // TODO: Initialize to an appropriate value Assert.IsTrue(target.GetValue(out value, true)); Assert.AreEqual(e, value); ((WeakReference)target._elementReference._elementReference).Target = null; Assert.IsFalse(target.GetValue(out value, true)); ((WeakReference)target._elementReference._elementReference).Target = WeakKey <E> .NullValue; Assert.IsTrue(target.GetValue(out value, true)); Assert.AreEqual(null, value); target._elementReference._elementReference = e; Assert.IsTrue(target.GetValue(out value, false)); Assert.AreEqual(e, value); }
public void SetIsCopiedFromPreviousSegment() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); segment.NavigationSource.Should().BeSameAs(set); }
private static KeySegment BuildKeySegment(IEdmEntityType entityType, IEdmEntitySetBase entitySet, object target) { if (entityType == null) { throw new ArgumentNullException("entityType"); } if (entitySet == null) { throw new ArgumentNullException("entitySet"); } if (target == null) { throw new ArgumentNullException("target"); } KeySegment keySegment = new KeySegment( entityType.Key().Select( (key) => { var keyValue = target.GetType().GetProperty(key.Name).GetValue(target, null); return(new KeyValuePair <string, object>(key.Name, keyValue)); }), entityType, entitySet); return(keySegment); }
/// <summary> ///A test for IsGarbage ///</summary> void IsGarbageTestHelper <E>(E e) where E : class { var target = new KeySegment <E, TrashableStub>() { _elementReference = new WeakKey <E> { _elementReference = new WeakReference(e) }, _tail = new TrashableStub() } ; Assert.IsFalse(target.IsGarbage); target._tail._isGarbage = true; Assert.IsTrue(target.IsGarbage); target._tail._isGarbage = false; ((WeakReference)target._elementReference._elementReference).Target = null; Assert.IsTrue(target.IsGarbage); target.SetValue(null, true); Assert.IsFalse(target.IsGarbage); }
public void TryTranslateKeySegmentTemplate_ReturnsODataKeySegment() { // Arrange EdmModel model = new EdmModel(); model.AddElement(_customerType); model.AddElement(_container); IDictionary <string, string> keys = new Dictionary <string, string> { { "customerId", "{key}" } }; KeySegmentTemplate template = new KeySegmentTemplate(keys, _customerType, _customers); ODataTemplateTranslateContext context = new ODataTemplateTranslateContext { RouteValues = new RouteValueDictionary(new { key = "42" }), Model = model }; // Act bool ok = template.TryTranslate(context); // Assert Assert.True(ok); ODataPathSegment actual = Assert.Single(context.Segments); KeySegment keySegment = Assert.IsType <KeySegment>(actual); var actualKey = Assert.Single(keySegment.Keys); Assert.Equal("customerId", actualKey.Key); Assert.Equal(42, actualKey.Value); }
/// <summary> /// Translate KeySegment to linq expression. /// </summary> /// <param name="segment">The KeySegment</param> /// <returns>The linq expression</returns> public override Expression Translate(KeySegment segment) { // translate to be ResultExpressionFromEntitySetSegment.Where(id -> id == keyVale).Single() Type instanceType = null; if (segment.EdmType.TypeKind == EdmTypeKind.Primitive) { instanceType = EdmLibraryExtensions.GetPrimitiveClrType((IEdmPrimitiveTypeReference)segment.EdmType.ToTypeReference(false)); } ParameterExpression parameter = Expression.Parameter(instanceType, "it"); Expression body = null; foreach (var key in segment.Keys) { var propertyAccessExpression = Expression.Property(parameter, instanceType, key.Key); Expression keyPredicate = Expression.Equal(propertyAccessExpression, Expression.Constant(key.Value)); if (body == null) { body = keyPredicate; } else { body = Expression.AndAlso(body, keyPredicate); } } Expression whereResult = Expression.Call(typeof(Queryable), WhereMethodName, new Type[] { instanceType }, this.ResultExpression, Expression.Quote(Expression.Lambda(body, parameter))); this.ResultExpression = Expression.Call(typeof(Queryable), SingleMethodName, new Type[] { instanceType }, whereResult); return(this.ResultExpression); }
/// <summary> /// Handle a KeySegment /// </summary> /// <param name="segment">the segment to handle</param> public override void Handle(KeySegment segment) { _navigationSource = segment.NavigationSource; if (_pathTemplate.Last() == ODataSegmentKinds.Ref) { _pathTemplate.Insert(_pathTemplate.Count - 1, ODataSegmentKinds.Key); } else { _pathTemplate.Add(ODataSegmentKinds.Key); } string value = ConvertKeysToString(segment.Keys, segment.EdmType); // update the previous segment Uri literal if (!_pathUriLiteral.Any()) { _pathUriLiteral.Add("(" + value + ")"); return; } if (_pathUriLiteral.Last() == ODataSegmentKinds.Ref) { _pathUriLiteral[_pathUriLiteral.Count - 2] = _pathUriLiteral[_pathUriLiteral.Count - 2] + "(" + value + ")"; } else { _pathUriLiteral[_pathUriLiteral.Count - 1] = _pathUriLiteral[_pathUriLiteral.Count - 1] + "(" + value + ")"; } }
public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup <string, HttpActionDescriptor> actionMap) { if (odataPath == null || controllerContext == null || actionMap == null) { return(null); } if (controllerContext.Request.Method != HttpMethod.Put) { return(null); } if (odataPath.PathTemplate != "~/entityset/key/navigation") { return(null); } KeySegment keySegment = odataPath.Segments[1] as KeySegment; controllerContext.RouteData.Values[ODataRouteConstants.Key] = keySegment.Keys.First().Value; NavigationPropertySegment navSegment = odataPath.Segments[2] as NavigationPropertySegment; return("PutTo" + navSegment.NavigationProperty.Name); }
public void CtorKeySegmentTemplate_SetsProperties_ForCompositeKeys() { // Arrange & Act EdmEntityType customerType = new EdmEntityType("NS", "Customer"); EdmStructuralProperty firstProperty = customerType.AddStructuralProperty("firstName", EdmPrimitiveTypeKind.String); EdmStructuralProperty lastProperty = customerType.AddStructuralProperty("lastName", EdmPrimitiveTypeKind.String); customerType.AddKeys(firstProperty, lastProperty); IDictionary <string, object> keys = new Dictionary <string, object> { { "firstName", "{key1}" }, { "lastName", "{key2}" } }; KeySegment segment = new KeySegment(keys, customerType, null); KeySegmentTemplate template = new KeySegmentTemplate(segment); // Assert Assert.Collection(template.KeyMappings, e => { Assert.Equal("firstName", e.Key); Assert.Equal("key1", e.Value); }, e => { Assert.Equal("lastName", e.Key); Assert.Equal("key2", e.Value); }); }
public void CtorKeySegmentTemplate_ForAlternateKey_SetsProperties() { // Arrange & Act IDictionary <string, object> keys = new Dictionary <string, object> { { "name", BuildExpression("{nameValue}") } }; KeySegment keySegment = new KeySegment(keys, _customerType, _customers); IEdmStructuralProperty nameProperty = _customerType.StructuralProperties().First(c => c.Name == "Name"); IDictionary <string, IEdmProperty> properties = new Dictionary <string, IEdmProperty> { { "name", nameProperty } }; KeySegmentTemplate segmentTemplate = new KeySegmentTemplate(keySegment, properties); // Assert KeyValuePair <string, string> keyMapping = Assert.Single(segmentTemplate.KeyMappings); Assert.Equal("name", keyMapping.Key); Assert.Equal("nameValue", keyMapping.Value); KeyValuePair <string, IEdmProperty> keyProperty = Assert.Single(segmentTemplate.KeyProperties); Assert.Equal("name", keyProperty.Key); Assert.Equal("Name", keyProperty.Value.Name); Assert.Same(_customers, segmentTemplate.NavigationSource); Assert.Same(_customerType, segmentTemplate.EntityType); Assert.Equal(1, segmentTemplate.Count); }
public void TryMatchMediaType_WithNonRawvalueRequest_DoesntMatchRequest() { IEdmModel model = ODataTestUtil.GetEdmModel(); IEdmEntitySet people = model.EntityContainer.FindEntitySet("People"); IEdmEntityType personType = model.SchemaElements.OfType <IEdmEntityType>().First(e => e.Name == "FormatterPerson"); IEdmStructuralProperty ageProperty = personType.FindProperty("Age") as IEdmStructuralProperty; Assert.NotNull(ageProperty); // Guard PropertySegment propertySegment = new PropertySegment(ageProperty); var keys = new[] { new KeyValuePair <string, object>("PerId", 1) }; KeySegment keySegment = new KeySegment(keys, personType, people); ODataPath path = new ODataPath(new EntitySetSegment(people), keySegment, propertySegment); ODataPrimitiveValueMediaTypeMapping mapping = new ODataPrimitiveValueMediaTypeMapping(); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/People(1)/Age/"); request.ODataContext().Path = path; double mapResult = mapping.TryMatchMediaType(request); Assert.Equal(0, mapResult); }
/// <summary> /// Add a key value to the route data. /// </summary> public void AddKeyValueToRouteData(KeySegment segment, string keyName = "key") { foreach (var keyValuePair in segment.Keys) { object value = keyValuePair.Value; ConstantNode node = value as ConstantNode; if (node != null) { ODataEnumValue enumValue = node.Value as ODataEnumValue; if (enumValue != null) { value = ODataUriUtils.ConvertToUriLiteral(enumValue, ODataVersion.V4); } } if (segment.Keys.Count() == 1) { RouteData[keyName] = value; } else { RouteData[keyValuePair.Key] = value; } } }
public async Task VisitAsync(ODataPath path) { NotFound = false; BadRequest = false; Result = null; ResultType = null; PropertySetter = null; Index = 0; foreach (var segment in path) { await(segment switch { TypeSegment typeSegment => VisitAsync(typeSegment), NavigationPropertySegment navigationPropertySegment => VisitAsync(navigationPropertySegment), EntitySetSegment entitySetSegment => VisitAsync(entitySetSegment), SingletonSegment singletonSegment => VisitAsync(singletonSegment), KeySegment keySegment => VisitAsync(keySegment), PropertySegment propertySegment => VisitAsync(propertySegment), AnnotationSegment annotationSegment => VisitAsync(annotationSegment), OperationImportSegment operationImportSegment => VisitAsync(operationImportSegment), OperationSegment operationSegment => VisitAsync(operationSegment), DynamicPathSegment dynamicPathSegment => VisitAsync(dynamicPathSegment), CountSegment countSegment => VisitAsync(countSegment), FilterSegment filterSegment => VisitAsync(filterSegment), ReferenceSegment referenceSegment => VisitAsync(referenceSegment), EachSegment eachSegment => VisitAsync(eachSegment), NavigationPropertyLinkSegment navigationPropertyLinkSegment => VisitAsync(navigationPropertyLinkSegment), ValueSegment valueSegment => VisitAsync(valueSegment), BatchSegment batchSegment => VisitAsync(batchSegment), BatchReferenceSegment batchReferenceSegment => VisitAsync(batchReferenceSegment), MetadataSegment metadataSegment => VisitAsync(metadataSegment), PathTemplateSegment pathTemplateSegment => VisitAsync(pathTemplateSegment), _ => throw new NotSupportedException() });
public void TypeIsSetCorrectly() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); segment.EdmType.Should().BeSameAs(set.EntityType()); }
public void CtorKeySegmentTemplate_SetsProperties() { // 1) Arrange & Act IDictionary <string, string> keys1 = new Dictionary <string, string> { { "customerId", "{key}" } }; KeySegmentTemplate segment1 = new KeySegmentTemplate(keys1, _customerType, _customers); // 2) Arrange & Act IDictionary <string, object> keys2 = new Dictionary <string, object> { { "customerId", BuildExpression("{key}") } }; KeySegment keySegment = new KeySegment(keys2, _customerType, _customers); KeySegmentTemplate segment2 = new KeySegmentTemplate(keySegment); // Assert foreach (var segment in new[] { segment1, segment2 }) { KeyValuePair <string, string> keyMapping = Assert.Single(segment.KeyMappings); Assert.Equal("customerId", keyMapping.Key); Assert.Equal("key", keyMapping.Value); KeyValuePair <string, IEdmProperty> keyProperty = Assert.Single(segment.KeyProperties); Assert.Equal("customerId", keyProperty.Key); Assert.Equal("customerId", keyProperty.Value.Name); Assert.Same(_customers, segment.NavigationSource); Assert.Same(_customerType, segment.EntityType); Assert.Equal(1, segment.Count); } }
public void TryMatchMediaType_DoesnotMatchRequest_ODataEnumValueMediaTypeMappingWithNonRawvalueRequest() { // Arrange IEdmModel model = GetEnumModel(); IEdmEntitySet enumEntity = model.EntityContainer.FindEntitySet("EnumEntity"); IEdmEntityType enumEntityType = model.SchemaElements.OfType <IEdmEntityType>().First(e => e.Name == "EnumEntity"); IEdmStructuralProperty property = enumEntityType.FindProperty("EnumProperty") as IEdmStructuralProperty; Assert.NotNull(property); // Guard PropertySegment propertySegment = new PropertySegment(property); var keys = new[] { new KeyValuePair <string, object>("Id", 1) }; KeySegment keySegment = new KeySegment(keys, enumEntityType, enumEntity); ODataPath path = new ODataPath(new EntitySetSegment(enumEntity), keySegment, propertySegment); ODataEnumValueMediaTypeMapping mapping = new ODataEnumValueMediaTypeMapping(); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/EnumEntity(1)/EnumProperty/"); request.ODataContext().Path = path; // Act double mapResult = mapping.TryMatchMediaType(request); // Assert Assert.Equal(0, mapResult); }
/// <summary> /// Translate a KeySegment /// </summary> /// <param name="segment">the segment to Translate</param> /// <returns>Defined by the implementer.</returns> public override string Translate(KeySegment segment) { Debug.Assert(segment != null, "segment != null"); List <KeyValuePair <string, object> > keys = segment.Keys.ToList(); StringBuilder builder = new StringBuilder(); builder.Append("("); for (int i = 0; i < keys.Count; i++) { if (i != 0) { builder.Append(","); } if (keys.Count == 1) { builder.Append(ODataUriUtils.ConvertToUriLiteral(keys[i].Value, ODataVersion.V4, DataSourceManager.GetCurrentDataSource().Model)); } else { builder.Append(string.Format("{0}={1}", keys[i].Key, ODataUriUtils.ConvertToUriLiteral(keys[i].Value, ODataVersion.V4, DataSourceManager.GetCurrentDataSource().Model))); } } builder.Append(")"); return(builder.ToString()); }
/// <inheritdoc/> internal static string SelectActionImpl(ODataPath odataPath, IWebApiControllerContext controllerContext, IWebApiActionMap actionMap) { if (ODataRequestMethod.Post == controllerContext.Request.Method) { switch (odataPath.PathTemplate) { case "~/entityset/key/cast/action": case "~/entityset/key/action": string actionName = GetAction(odataPath).SelectAction(actionMap, isCollection: false); if (actionName != null) { KeySegment keySegment = (KeySegment)odataPath.Segments[1]; controllerContext.AddKeyValueToRouteData(keySegment); } return(actionName); case "~/entityset/cast/action": case "~/entityset/action": return(GetAction(odataPath).SelectAction(actionMap, isCollection: true)); case "~/singleton/action": case "~/singleton/cast/action": return(GetAction(odataPath).SelectAction(actionMap, isCollection: false)); } } return(null); }
public override bool TryTranslate(ODataTemplateTranslateContext context) { if (!context.RouteValues.TryGetValue("navigation", out object navigationNameObj)) { return(false); } string navigationName = navigationNameObj as string; KeySegment keySegment = context.Segments.Last() as KeySegment; IEdmEntityType entityType = keySegment.EdmType as IEdmEntityType; IEdmNavigationProperty navigationProperty = entityType.NavigationProperties().FirstOrDefault(n => n.Name == navigationName); if (navigationProperty != null) { var navigationSource = keySegment.NavigationSource; IEdmNavigationSource targetNavigationSource = navigationSource.FindNavigationTarget(navigationProperty); NavigationPropertySegment seg = new NavigationPropertySegment(navigationProperty, navigationSource); context.Segments.Add(seg); return(true); } return(false); }
public override string SelectAction(Microsoft.AspNet.OData.Routing.ODataPath odataPath, HttpControllerContext controllerContext, ILookup <string, HttpActionDescriptor> actionMap) { if (odataPath == null || controllerContext == null || actionMap == null) { return(null); } if (odataPath.PathTemplate != "~/entityset/key/navigation" && odataPath.PathTemplate != "~/entityset/key/cast/navigation") { return(base.SelectAction(odataPath, controllerContext, actionMap)); } if (!controllerContext.ControllerDescriptor.ControllerType.IsSubclassOfRawGeneric(typeof(GenericDataController <>))) { return(base.SelectAction(odataPath, controllerContext, actionMap)); } var segment = odataPath.Segments[odataPath.Segments.Count - 1] as NavigationPropertySegment; if (segment != null) { if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal)) { KeySegment keyValueSegment = odataPath.Segments[1] as KeySegment; controllerContext.RouteData.Values[ODataRouteConstants.Key] = keyValueSegment.GenerateKey(); } } return(null); }
public void Translate_ReturnsODataKeySegment() { // Arrange EdmModel model = new EdmModel(); model.AddElement(_customerType); model.AddElement(_container); IDictionary <string, string> keys = new Dictionary <string, string> { { "customerId", "{key}" } }; RouteValueDictionary routeValueDictionary = new RouteValueDictionary(new { key = "42" }); KeySegmentTemplate template = new KeySegmentTemplate(keys, _customerType, _customers); HttpContext httpContext = new DefaultHttpContext(); ODataTemplateTranslateContext context = new ODataTemplateTranslateContext(httpContext, routeValueDictionary, model); // Act ODataPathSegment actual = template.Translate(context); // Assert Assert.NotNull(actual); KeySegment keySegment = Assert.IsType <KeySegment>(actual); var actualKey = Assert.Single(keySegment.Keys); Assert.Equal("customerId", actualKey.Key); Assert.Equal(42, actualKey.Value); }
public void TryMatchMediaTypeWithBinaryRawValueMatchesRequest() { IEdmModel model = GetBinaryModel(); IEdmEntitySet rawValues = model.EntityContainer.FindEntitySet("RawValue"); IEdmEntityType rawValueEntity = model.SchemaElements.OfType <IEdmEntityType>().First(e => e.Name == "RawValueEntity"); IEdmStructuralProperty property = rawValueEntity.FindProperty("BinaryProperty") as IEdmStructuralProperty; Assert.NotNull(property); // Guard PropertySegment propertySegment = new PropertySegment(property); var keys = new[] { new KeyValuePair <string, object>("Id", 1) }; KeySegment keySegment = new KeySegment(keys, rawValueEntity, rawValues); ODataPath path = new ODataPath(new EntitySetSegment(rawValues), keySegment, propertySegment, new ValueSegment(propertySegment.EdmType)); ODataBinaryValueMediaTypeMapping mapping = new ODataBinaryValueMediaTypeMapping(); var request = RequestFactory.Create(HttpMethod.Get, "http://localhost/RawValue(1)/BinaryProperty/$value"); request.ODataContext().Path = path; double mapResult = mapping.TryMatchMediaType(request); Assert.Equal(1.0, mapResult); }
public void SetIsCopiedFromPreviousSegment() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); Assert.Same(set, segment.NavigationSource); }
public void TypeIsSetCorrectly() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); Assert.Same(set.EntityType(), segment.EdmType); }
public void ODataPathSegmentToTemplateHandler_Throws_WithoutAlternateKey() { // Arrange EdmModel model = new EdmModel(); EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); customer.AddStructuralProperty("Code", EdmPrimitiveTypeKind.Int32); model.AddElement(customer); EdmEntityContainer entityContainer = new EdmEntityContainer("NS", "Default"); EdmEntitySet customers = entityContainer.AddEntitySet("Customers", customer); model.AddElement(entityContainer); IDictionary <string, object> keys = new Dictionary <string, object> { { "Code", "{Code}" } }; KeySegment segment = new KeySegment(keys, customer, customers); ODataPathSegmentToTemplateHandler handler = new ODataPathSegmentToTemplateHandler(model); // Act Action test = () => handler.Handle(segment); // Assert ExceptionAssert.Throws <ODataException>(test, "Cannot find key 'Code' in the 'NS.Customer' type."); }
public void KeySetCorrectly() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); segment.Keys.Should().OnlyContain(x => x.Key == "key" && x.Value.As <string>() == "value"); }
public void ODataPathSegmentToTemplateHandler_Handles_Key() { // Arrange ODataPathSegmentToTemplateHandler handler = new ODataPathSegmentToTemplateHandler(null); EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.Int32)); EdmEntityContainer entityContainer = new EdmEntityContainer("NS", "Default"); EdmEntitySet customers = entityContainer.AddEntitySet("Customers", customer); IDictionary <string, object> keys = new Dictionary <string, object> { { "Id", "{key}" } }; KeySegment segment = new KeySegment(keys, customer, customers); // Act handler.Handle(segment); // Assert ODataSegmentTemplate segmentTemplate = Assert.Single(handler.Templates); Assert.IsType <KeySegmentTemplate>(segmentTemplate); }
/// <summary>Tries to create a key segment for the given filter if it is non empty.</summary> /// <param name="previous">Segment on which to compose.</param> /// <param name="previousKeySegment">The parent node's key segment.</param> /// <param name="parenthesisExpression">Parenthesis expression of segment.</param> /// <param name="keySegment">The key segment that was created if the key was non-empty.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <param name="resolver">The resolver to use.</param> /// <returns>Whether the key was non-empty.</returns> internal static bool TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, string parenthesisExpression, out ODataPathSegment keySegment, bool enableUriTemplateParsing = false, ODataUriResolver resolver = null) { Debug.Assert(parenthesisExpression != null, "parenthesisExpression != null"); Debug.Assert(previous != null, "segment!= null"); if (resolver == null) { resolver = ODataUriResolver.Default; } if (previous.SingleResult) { throw ExceptionUtil.CreateSyntaxError(); } SegmentArgumentParser key; if (!SegmentArgumentParser.TryParseKeysFromUri(parenthesisExpression, out key, enableUriTemplateParsing)) { throw ExceptionUtil.CreateSyntaxError(); } // People/NS.Employees() is OK, just like People() is OK if (key.IsEmpty) { keySegment = null; return false; } keySegment = CreateKeySegment(previous, previousKeySegment, key, resolver); return true; }
public void ODataPathSegmentHandler_Handles_KeySegment() { // Arrange ODataPathSegmentHandler handler = new ODataPathSegmentHandler(); EdmEntityType customer = new EdmEntityType("NS", "Customer"); customer.AddKeys(customer.AddStructuralProperty("Id", EdmPrimitiveTypeKind.String)); EdmEntityContainer entityContainer = new EdmEntityContainer("NS", "Default"); EdmEntitySet customers = entityContainer.AddEntitySet("Customers", customer); IDictionary <string, object> keys = new Dictionary <string, object> { { "Id", "abc" } }; KeySegment segment = new KeySegment(keys, customer, customers); // Act handler.Handle(segment); // Assert Assert.Equal("('abc')", handler.PathLiteral); Assert.Same(customers, handler.NavigationSource); }
/// <summary> /// Translate a KeySegment /// </summary> /// <param name="segment">the segment to Translate</param> /// <returns>Translated the path segment template.</returns> public override ODataSegmentTemplate Translate(KeySegment segment) { if (segment == null) { throw Error.ArgumentNull(nameof(segment)); } try { return(new KeySegmentTemplate(segment)); } catch { if (_model != null) { var alternateKeys = _model.ResolveAlternateKeyProperties(segment); if (alternateKeys != null) { return(new KeySegmentTemplate(segment, alternateKeys)); } } throw; } }
public void EqualityIsCorrect() { List<KeyValuePair<string, object>> key1 = new List<KeyValuePair<string, object>>() {new KeyValuePair<string, object>("key", "value")}; List<KeyValuePair<string, object>> key2 = new List<KeyValuePair<string, object>>() { new KeyValuePair<string, object>("key", "value") }; KeySegment segment1 = new KeySegment(key1, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet()); KeySegment segment2 = new KeySegment(key2, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet()); segment1.Equals(segment2).Should().BeTrue(); }
public void InequalityIsCorrect() { KeySegment segment1 = new KeySegment(new List<KeyValuePair<string, object>>() { new KeyValuePair<string, object>("key", "value1")}, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet()); KeySegment segment2 = new KeySegment(new List<KeyValuePair<string, object>>() {new KeyValuePair<string, object>("key", "value1")}, HardCodedTestModel.GetDogType(), HardCodedTestModel.GetDogsSet()); KeySegment segment3 = new KeySegment(new List<KeyValuePair<string, object>>() { new KeyValuePair<string, object>("key", "value2")}, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet()); CountSegment segment4 = CountSegment.Instance; segment1.Equals(segment2).Should().BeFalse(); segment1.Equals(segment3).Should().BeFalse(); segment1.Equals(segment4).Should().BeFalse(); }
/// <summary> /// Initializes a new instance of the <see cref="KeyValuePathSegment" /> class. /// </summary> /// <param name="segment">The key segment.</param> public KeyValuePathSegment(KeySegment segment) { if (segment == null) { throw Error.ArgumentNull("segment"); } Segment = segment; Value = segment.TranslateKeyValueToString(); }
/// <summary> /// Tries to handle the current segment as a key property value. /// </summary> /// <param name="segmentText">The segment text.</param> /// <param name="previous">The previous segment.</param> /// <param name="previousKeySegment">The parent node's key segment.</param> /// <param name="urlConvention">The current url convention for the server.</param> /// <param name="keySegment">The key segment that was created if the segment could be interpreted as a key.</param> /// <param name="enableUriTemplateParsing">Whether Uri template parsing is enabled.</param> /// <param name="resolver">The resolver to use.</param> /// <returns>Whether or not the segment was interpreted as a key.</returns> internal static bool TryHandleSegmentAsKey(string segmentText, ODataPathSegment previous, KeySegment previousKeySegment, UrlConvention urlConvention, out KeySegment keySegment, bool enableUriTemplateParsing = false, ODataUriResolver resolver = null) { Debug.Assert(previous != null, "previous != null"); Debug.Assert(urlConvention != null, "urlConvention != null"); if (resolver == null) { resolver = ODataUriResolver.Default; } keySegment = null; // If the current convention is not keys-as-segments, then this does not apply. if (!urlConvention.GenerateKeyAsSegment) { return false; } // Keys only apply to collections, so if the prior segment is already a singleton, do not treat this segment as a key. if (previous.SingleResult) { return false; } // System segments (ie '$count') are never keys. if (IsSystemSegment(segmentText)) { return false; } // If the previous type is not an entity collection type // TODO: collapse this and SingleResult. IEdmEntityType targetEntityType; if (previous.TargetEdmType == null || !previous.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType)) { return false; } // Previously KeyAsSegment only allows single key, but we can also leverage related key finder to auto fill // missed key value from referential constraint information, which would be done in CreateKeySegment. // CreateKeySegment method will check whether key properties are missing after taking in related key values. keySegment = CreateKeySegment(previous, previousKeySegment, SegmentArgumentParser.FromSegment(segmentText, enableUriTemplateParsing), resolver); return true; }
public void Translate_KeySegment_To_KeyValuePathSegment_Works() { // Arrange IEdmEntityType entityType = _model.FindDeclaredType("System.Web.OData.Routing.RoutingCustomer") as IEdmEntityType; IEdmEntitySet entityset = _model.FindDeclaredEntitySet("RoutingCustomers"); KeySegment segment = new KeySegment(new[] { new KeyValuePair<string, object>("ID", 42) }, entityType, entityset); // Act IEnumerable<ODataPathSegment> segments = _translator.Translate(segment); // Assert ODataPathSegment pathSegment = Assert.Single(segments); KeyValuePathSegment keyValuePathSegment = Assert.IsType<KeyValuePathSegment>(pathSegment); Assert.Equal("42", keyValuePathSegment.Value); }
private static IReadOnlyDictionary<string, object> GetPathKeyValues( KeySegment keySegment) { var result = new Dictionary<string, object>(); // TODO GitHubIssue#42 : Improve key parsing logic // this parsing implementation does not allow key values to contain commas // Depending on the WebAPI to make KeyValuePathSegment.Values collection public // (or have the parsing logic public). var keyValuePairs = keySegment.Keys; foreach (var keyValuePair in keyValuePairs) { result.Add(keyValuePair.Key, keyValuePair.Value); } return result; }
/// <summary> /// Handle a KeySegment /// </summary> /// <param name="segment">the segment to Handle</param> public virtual void Handle(KeySegment segment) { throw new NotImplementedException(); }
private static KeySegment BuildKeySegment(IEdmEntityType entityType, IEdmEntitySetBase entitySet, object target) { if (entityType == null) { throw new ArgumentNullException("entityType"); } if (entitySet == null) { throw new ArgumentNullException("entitySet"); } if (target == null) { throw new ArgumentNullException("target"); } KeySegment keySegment = new KeySegment( entityType.Key().Select( (key) => { var keyValue = target.GetType().GetProperty(key.Name).GetValue(target, null); return new KeyValuePair<string, object>(key.Name, keyValue); }), entityType, entitySet); return keySegment; }
/// <summary> /// Append the key segment in the end of ODataPath, the method does not modify current ODataPath instance, /// it returns a new ODataPath without ending type segment. /// If last segment is type cast, the key would be appended before type cast segment. /// </summary> /// <param name="path">Path to perform the computation on.</param> /// <param name="keys">The set of key property names and the values to be used in searching for the given item.</param> /// <param name="edmType">The type of the item this key returns.</param> /// <param name="navigationSource">The navigation source that this key is used to search.</param> /// <returns>The ODataPath with key segment appended</returns> public static ODataPath AppendKeySegment(this ODataPath path, IEnumerable<KeyValuePair<string, object>> keys, IEdmEntityType edmType, IEdmNavigationSource navigationSource) { var handler = new SplitEndingSegmentOfTypeHandler<TypeSegment>(); path.WalkWith(handler); KeySegment keySegment = new KeySegment(keys, edmType, navigationSource); ODataPath newPath = handler.FirstPart; newPath.Add(keySegment); foreach (var segment in handler.LastPart) { newPath.Add(segment); } return newPath; }
/// <summary> /// Parses the key properties based on the segment's target type, then creates a new segment for the key. /// </summary> /// <param name="segment">The segment to apply the key to.</param> /// <param name="previousKeySegment">The parent node's key segment.</param> /// <param name="key">The key to apply.</param> /// <param name="resolver">The resolver to use.</param> /// <returns>The newly created key segment.</returns> private static KeySegment CreateKeySegment(ODataPathSegment segment, KeySegment previousKeySegment, SegmentArgumentParser key, ODataUriResolver resolver) { Debug.Assert(segment != null, "segment != null"); Debug.Assert(key != null && !key.IsEmpty, "key != null && !key.IsEmpty"); Debug.Assert(segment.SingleResult == false, "segment.SingleResult == false"); IEdmEntityType targetEntityType = null; if (!(segment.TargetEdmType != null && segment.TargetEdmType.IsEntityOrEntityCollectionType(out targetEntityType))) { throw ExceptionUtil.CreateSyntaxError(); } Debug.Assert(targetEntityType != null, "targetEntityType != null"); // Make sure the keys specified in the uri matches with the number of keys in the metadata var keyProperties = targetEntityType.Key().ToList(); if (keyProperties.Count != key.ValueCount) { NavigationPropertySegment currentNavPropSegment = segment as NavigationPropertySegment; if (currentNavPropSegment != null) { key = KeyFinder.FindAndUseKeysFromRelatedSegment(key, keyProperties, currentNavPropSegment.NavigationProperty, previousKeySegment); } // if we still didn't find any keys, then throw an error. if (keyProperties.Count != key.ValueCount && resolver.GetType() == typeof(ODataUriResolver)) { throw ExceptionUtil.CreateBadRequestError(ErrorStrings.BadRequest_KeyCountMismatch(targetEntityType.FullName())); } } if (!key.AreValuesNamed && key.ValueCount > 1 && resolver.GetType() == typeof(ODataUriResolver)) { throw ExceptionUtil.CreateBadRequestError(ErrorStrings.RequestUriProcessor_KeysMustBeNamed); } IEnumerable<KeyValuePair<string, object>> keyPairs; if (!key.TryConvertValues(targetEntityType, out keyPairs, resolver)) { throw ExceptionUtil.CreateSyntaxError(); } IEdmEntityType entityType; bool isEntity = segment.TargetEdmType.IsEntityOrEntityCollectionType(out entityType); Debug.Assert(isEntity, "Key target type should be an entity type."); var keySegment = new KeySegment(keyPairs, entityType, segment.TargetEdmNavigationSource); keySegment.CopyValuesFrom(segment); keySegment.SingleResult = true; return keySegment; }
/// <summary> /// Find any related keys from the parent key segment, if it exists, and add them to the raw key values that /// we already have from the uri. /// </summary> /// <param name="rawKeyValuesFromUri">The raw key values as we've parsed them from the uri.</param> /// <param name="targetEntityKeyProperties">The list of key properties on the target entity.</param> /// <param name="currentNavigationProperty">The current navigation property that we're trying to follow using the raw key values</param> /// <param name="keySegmentOfParentEntity">The key segment of the parent entity in this path, if it exists. Null otherwise</param> /// <returns>A new SegmentArgumentParser with any keys that were found added to its list of NamedValues.</returns> /// <throws>Thorws if the input currentNavigationProperty is null.</throws> public static SegmentArgumentParser FindAndUseKeysFromRelatedSegment(SegmentArgumentParser rawKeyValuesFromUri, IEnumerable<IEdmStructuralProperty> targetEntityKeyProperties, IEdmNavigationProperty currentNavigationProperty, KeySegment keySegmentOfParentEntity) { ExceptionUtils.CheckArgumentNotNull(currentNavigationProperty, "currentNavigationProperty"); ExceptionUtils.CheckArgumentNotNull(rawKeyValuesFromUri, "rawKeyValuesFromUri"); ReadOnlyCollection<IEdmStructuralProperty> targetKeyPropertyList = targetEntityKeyProperties != null ? new ReadOnlyCollection<IEdmStructuralProperty>(targetEntityKeyProperties.ToList()) : new ReadOnlyCollection<IEdmStructuralProperty>(new List<IEdmStructuralProperty>()); // should only get here if the number of raw parameters from the uri is different than the number of key properties for the target entity. Debug.Assert(rawKeyValuesFromUri.ValueCount < targetKeyPropertyList.Count(), "rawKeyValuesFromUri.ValueCount < targetEntityKeyProperties.Count()"); // if the raw key from the uri has positional values, there must be only one of them // its important to cache this value here because we'll change it when we add new // named values below (the implementation of AreValuesNamed is just namedValues !=null) bool hasPositionalValues = !rawKeyValuesFromUri.AreValuesNamed; if (hasPositionalValues && rawKeyValuesFromUri.ValueCount > 1) { return rawKeyValuesFromUri; } if (keySegmentOfParentEntity == null) { return rawKeyValuesFromUri; } // TODO: p2 merge the below 2 pieces of codes // find out if any target entity key properties have referential constraints that link them to the previous rawKeyValuesFromUri. List<EdmReferentialConstraintPropertyPair> keysFromReferentialIntegrityConstraint = ExtractMatchingPropertyPairsFromNavProp(currentNavigationProperty, targetKeyPropertyList).ToList(); foreach (EdmReferentialConstraintPropertyPair keyFromReferentialIntegrityConstraint in keysFromReferentialIntegrityConstraint) { KeyValuePair<string, object> valueFromParent = keySegmentOfParentEntity.Keys.SingleOrDefault(x => x.Key == keyFromReferentialIntegrityConstraint.DependentProperty.Name); if (valueFromParent.Key != null) { // if the key from the referential integrity constraint is one of the target key properties // and that key property isn't already populated in the raw key values from the uri, then // we set that value to the value from the parent key segment. if (targetKeyPropertyList.Any(x => x.Name == keyFromReferentialIntegrityConstraint.PrincipalProperty.Name)) { rawKeyValuesFromUri.AddNamedValue( keyFromReferentialIntegrityConstraint.PrincipalProperty.Name, valueFromParent.Value.ToString()); } } } // also need to look to see if any nav props exist in the target set that refer back to this same set, which might have // referential constraints also. keysFromReferentialIntegrityConstraint.Clear(); IEdmNavigationProperty reverseNavProp = currentNavigationProperty.Partner; if (reverseNavProp != null) { keysFromReferentialIntegrityConstraint.AddRange(ExtractMatchingPropertyPairsFromReversedNavProp(reverseNavProp, targetKeyPropertyList)); } foreach (EdmReferentialConstraintPropertyPair keyFromReferentialIntegrityConstraint in keysFromReferentialIntegrityConstraint) { KeyValuePair<string, object> valueFromParent = keySegmentOfParentEntity.Keys.SingleOrDefault(x => x.Key == keyFromReferentialIntegrityConstraint.PrincipalProperty.Name); if (valueFromParent.Key != null) { // if the key from the referential integrity constraint is one of the target key properties // and that key property isn't already populated in the raw key values from the uri, then // we set that value to the value from the parent key segment. if (targetKeyPropertyList.Any(x => x.Name == keyFromReferentialIntegrityConstraint.DependentProperty.Name)) { rawKeyValuesFromUri.AddNamedValue( keyFromReferentialIntegrityConstraint.DependentProperty.Name, valueFromParent.Value.ToString()); } } } // if we had a positional value before, then we need to add that value as a new named value. // the name that we choose will be the only value from the target entity key properties // that isn't already set in the NamedValues list. if (hasPositionalValues) { if (rawKeyValuesFromUri.NamedValues != null) { List<IEdmStructuralProperty> unassignedProperties = targetKeyPropertyList.Where(x => !rawKeyValuesFromUri.NamedValues.ContainsKey(x.Name)).ToList(); if (unassignedProperties.Count == 1) { rawKeyValuesFromUri.AddNamedValue(unassignedProperties[0].Name, rawKeyValuesFromUri.PositionalValues[0]); } else { return rawKeyValuesFromUri; } // clear out the positional value so that we keep a consistent state in the // raw keys from uri. rawKeyValuesFromUri.PositionalValues.Clear(); } else { return rawKeyValuesFromUri; } } return rawKeyValuesFromUri; }
/// <summary> /// Build canonical URI base on current query target /// </summary> /// <param name="rootUri">The root URI</param> /// <param name="keySegment">The additional key segment of current target.</param> /// <returns>The canonical URI</returns> public Uri BuildCanonicalUri(Uri rootUri, KeySegment keySegment) { List<ODataPathSegment> segments = new List<ODataPathSegment>(this.canonicalSegments); if (keySegment != null && this.IsEntitySet) { if (segments.Last() is TypeSegment) { segments.Insert(segments.Count - 1, keySegment); } else { segments.Add(keySegment); } } ODataPath path = new ODataPath(segments); return new Uri(rootUri, string.Concat(path.WalkWith(PathSegmentToResourcePathTranslator.Instance)).TrimStart('/')); }
public void KeySetCorrectly() { var set = ModelBuildingHelpers.BuildValidEntitySet(); KeySegment segment = new KeySegment(Key, set.EntityType(), set); segment.Keys.Should().OnlyContain(x => x.Key == "key" && x.Value.As<string>() == "value"); }
/// <summary>Selects a single resource by key values.</summary> /// <param name="queryExpression">Base query for resources</param> /// <param name="resourceType">resource type whose keys are specified</param> /// <param name="key">Key values for the given resource type.</param> /// <returns>A new query that selects the single resource that matches the specified key values.</returns> private static Expression SelectResourceByKey(Expression queryExpression, ResourceType resourceType, KeySegment key) { Debug.Assert(queryExpression != null, "queryExpression != null"); Debug.Assert(key != null, "key != null"); List<KeyValuePair<string, object>> keyValues = key.Keys.ToList(); Debug.Assert(keyValues.Count != 0, "keyValues.Count != 0"); Debug.Assert(resourceType.KeyProperties.Count == keyValues.Count, "resourceType.KeyProperties.Count == keyValues.Count"); for (int i = 0; i < resourceType.KeyProperties.Count; i++) { ResourceProperty keyProperty = resourceType.KeyProperties[i]; Debug.Assert(keyProperty.IsOfKind(ResourcePropertyKind.Key), "keyProperty.IsOfKind(ResourcePropertyKind.Key)"); object keyValue; if (keyValues.Count == 0) { keyValue = keyValues[0].Value; } else { keyValue = keyValues.Single(v => v.Key == keyProperty.Name).Value; } var binaryValue = keyValue as byte[]; if (binaryValue != null && keyProperty.Type == typeof(System.Data.Linq.Binary)) { keyValue = new System.Data.Linq.Binary(binaryValue); } var stringValue = keyValue as string; if (stringValue != null && keyProperty.Type == typeof(XElement)) { keyValue = XElement.Parse(stringValue); } if (keyProperty.Type == typeof(DateTime)) { Debug.Assert(keyValue != null && keyValue is DateTimeOffset, "For DateTime properties, the value must be read as DateTimeOffset"); keyValue = WebUtil.ConvertDateTimeOffsetToDateTime((DateTimeOffset)keyValue); } ParameterExpression parameter = Expression.Parameter(queryExpression.ElementType(), "element"); Expression e; if (keyProperty.CanReflectOnInstanceTypeProperty) { e = Expression.Property(parameter, keyProperty.Name); } else { e = Expression.Call(null /*instance*/, DataServiceProviderMethods.GetValueMethodInfo, parameter, Expression.Constant(keyProperty)); e = Expression.Convert(e, keyProperty.Type); } BinaryExpression body = Expression.Equal(e, Expression.Constant(keyValue)); LambdaExpression predicate = Expression.Lambda(body, parameter); queryExpression = queryExpression.QueryableWhere(predicate); } return queryExpression; }
public override void Handle(KeySegment segment) { this.ThrowIfResolved(); this.Type = segment.EdmType; this.ElementType = this.GetElementType(this.Type); this.PushParentSegment(); this.childSegments.Add(segment); this.canonicalSegments.Add(segment); }