public void IfNoReferentialIntegrityConstraintExistsOnPartnerKeyIsUnchanged() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetDogIdProp() }, HardCodedTestModel.GetEmployeeOfficeDogNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.Should().Be(key); }
public void IfValueExistsInTargetPropertiesAndNotExistingKeysItIsNotWritten() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("0", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property(), }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("Name", "Stuff") }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.Should().Be(key); }
public void AreValuesNamedIsAlwaysSet() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.AreValuesNamed.Should().BeTrue(); }
public void PositionalValuesArrayIsCleared() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); Assert.Empty(newKey.PositionalValues); }
public void IfValueExistsinExistingKeysButNotTargetPropertiesItIsNotWritten() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("0", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId2Property(), HardCodedTestModel.GetLionAttackDatesProp() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); Assert.Same(key, newKey); }
public void LookForKeysOnBothCurrentNavPropAndPartnerIfItExistsWorksForTemplate() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("{6}", out key, true); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetDogLionWhoAteMeNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.NamedValues.Should().Contain(new KeyValuePair <string, string>("ID1", "32")) .And.Contain(new KeyValuePair <string, string>("ID2", "{6}")); }
public void PositionalValueNotAddedIfMoreThanOneMissingValueExists() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property(), HardCodedTestModel.GetLionAttackDatesProp() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.Should().Be(key); }
public void PositionalValueAddedAsMissingValueIfOnlyOneMissingValueExists() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.NamedValues.Should().Contain(new KeyValuePair <string, string>("ID1", "32")) .And.Contain(new KeyValuePair <string, string>("ID2", "6")); }
public void IfValueAlreadySpecifiedInRawKeyItIsNotOverwritten() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("ID1=6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetPersonMyLionsNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); newKey.NamedValues.Should().ContainKey("ID1") .And.ContainValue("6"); }
public void LookForKeysOnBothCurrentNavPropAndPartnerIfItExists() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("6", out key, false); var newKey = KeyFinder.FindAndUseKeysFromRelatedSegment( key, new List <IEdmStructuralProperty>() { HardCodedTestModel.GetLionId1Property(), HardCodedTestModel.GetLionId2Property() }, HardCodedTestModel.GetDogLionWhoAteMeNavProp(), new KeySegment( new List <KeyValuePair <string, object> >() { new KeyValuePair <string, object>("ID", 32) }, HardCodedTestModel.GetPersonType(), HardCodedTestModel.GetPeopleSet())); Assert.Contains(newKey.NamedValues, kvp => kvp.Key == "ID1" && kvp.Value == "32"); Assert.Contains(newKey.NamedValues, kvp => kvp.Key == "ID2" && kvp.Value == "6"); }
public void TestTemplateKeyParsingWithTemplateParsingDisabled() { SegmentArgumentParser key; SegmentArgumentParser.TryParseKeysFromUri("ID={K0}", out key, false).Should().BeFalse(); }
/// <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; }