예제 #1
0
        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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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();
        }
예제 #4
0
        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);
        }
예제 #5
0
        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);
        }
예제 #6
0
        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}"));
        }
예제 #7
0
        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);
        }
예제 #8
0
        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"));
        }
예제 #9
0
        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");
        }
예제 #10
0
        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");
        }
예제 #11
0
        public void TestTemplateKeyParsingWithTemplateParsingDisabled()
        {
            SegmentArgumentParser key;

            SegmentArgumentParser.TryParseKeysFromUri("ID={K0}", out key, false).Should().BeFalse();
        }
예제 #12
0
        /// <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;
        }
예제 #13
0
        /// <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;
        }