Esempio n. 1
0
        private void UpdateVisibleEntitiesGraphForEntity(QueryStructuralValue entityValue, string path, string[] spanPaths)
        {
            if (!this.VisibleEntitiesGraph.ContainsKey(entityValue))
            {
                if (entityValue.IsNull)
                {
                    this.VisibleEntitiesGraph[entityValue] = entityValue;

                    return;
                }
                else
                {
                    var visibleEntity = entityValue.Type.CreateNewInstance();
                    this.PopulateNonNavigationPropertiesOfVisibleEntity(entityValue, visibleEntity);
                    this.VisibleEntitiesGraph[entityValue] = visibleEntity;
                }
            }

            if (!entityValue.IsNull)
            {
                foreach (QueryProperty property in entityValue.Type.Properties)
                {
                    string newPath = this.CreateNewPath(path, property.Name);
                    if (this.IsValidSpanPath(newPath, spanPaths))
                    {
                        var originalValue = entityValue.GetValue(property.Name);
                        this.UpdateVisibleEntitiesGraphForQueryValue(originalValue, newPath, spanPaths);
                    }
                }
            }
        }
        /// <summary>
        /// Visits a QueryStructuralValue and returns the clr value of the structural value
        /// </summary>
        /// <param name="value">The QueryStructuralValue which contains the clr value of the structural type : complex/entity  type</param>
        /// <returns>The clr instance of the structural value</returns>
        public object Visit(QueryStructuralValue value)
        {
            object clrInstance = null;

            if (this.objectLookup.TryGetValue(value, out clrInstance))
            {
                return(clrInstance);
            }

            ExceptionUtilities.CheckObjectNotNull(value.Type as IQueryClrType, "Structural type does not implement IQueryClrType");

            IQueryClrType clrTypeQueryable = value.Type as IQueryClrType;
            Type          clrType          = clrTypeQueryable.ClrType;

            ExceptionUtilities.CheckObjectNotNull(clrType, "ClrType should not be null");

            clrInstance = clrType.GetConstructor(Type.EmptyTypes).Invoke(null);
            this.objectLookup.Add(value, clrInstance);

            foreach (var member in value.MemberNames)
            {
                QueryValue   queryValue     = value.GetValue(member);
                var          memberValue    = queryValue.Accept(this);
                PropertyInfo memberProperty = clrType.GetProperty(member);
                memberProperty.SetValue(clrInstance, memberValue, null);
            }

            return(clrInstance);
        }
Esempio n. 3
0
        /// <summary>
        /// Visits the QueryStructuralValue
        /// </summary>
        /// <param name="value">Value to visit</param>
        /// <returns>a string that represents a query structural value</returns>
        public string Visit(QueryStructuralValue value)
        {
            var indent          = this.GenerateIndent();
            var queryEntityType = value.Type as QueryEntityType;

            if (queryEntityType != null)
            {
                var idValue = this.LinkGenerator.GenerateEntityId(value).Replace(this.AstoriaServiceDescriptor.ServiceUri.AbsoluteUri, string.Empty);
                this.builder.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}Id:{1}", indent, idValue));

                // do not expand below configured level of expands likely writing out querydataset
                if (this.currentDepth > this.maxDepth)
                {
                    return(null);
                }

                foreach (var member in queryEntityType.Properties.Where(p => p.IsNavigationProperty()))
                {
                    var memberValue = value.GetValue(member.Name);
                    this.currentDepth++;
                    var childIndent = this.GenerateIndent();
                    this.builder.AppendLine(string.Format(CultureInfo.InvariantCulture, "{0}{1}", childIndent, member.Name));
                    this.currentDepth++;
                    memberValue.Accept(this);
                    this.currentDepth -= 2;
                }
            }

            return(null);
        }
Esempio n. 4
0
        /// <summary>
        /// Fixes up the properties of the structural value based on the given selected paths
        /// </summary>
        /// <param name="instance">The value to fix up</param>
        /// <param name="selectedPaths">The selected paths for the value's scope</param>
        /// <returns>The fixed-up value</returns>
        private QueryStructuralValue FixupPropertiesForSelect(QueryStructuralValue instance, IEnumerable <string> selectedPaths)
        {
            ExceptionUtilities.CheckArgumentNotNull(instance, "instance");
            ExceptionUtilities.CheckCollectionNotEmpty(selectedPaths, "selectedPaths");

            var entityType = instance.Type as QueryEntityType;

            ExceptionUtilities.CheckObjectNotNull(entityType, "Select is not supported on non-entity types");

            var masked = MaskedQueryStructuralValue.Create(instance);

            bool wildCard = selectedPaths.Contains(Endpoints.SelectAll);

            var propertyNames = entityType.EntityType.AllProperties.Select(p => p.Name).Concat(entityType.Properties.Streams().Select(m => m.Name));

            foreach (string propertyName in propertyNames)
            {
                if (!selectedPaths.Contains(Uri.EscapeDataString(propertyName)) && !wildCard)
                {
                    // Primitive, bag and stream properties are either entirely present or entirely missing.
                    // However, complex properties can be partially present if a mapped sub-property has a
                    // null value. For this reason, we recursively hide the property and all sub-properties.
                    HidePropertyRecursive(masked, propertyName);
                }
            }

            foreach (string propertyName in entityType.EntityType.AllNavigationProperties.Select(p => p.Name))
            {
                string pathMarker = Uri.EscapeDataString(propertyName) + "/";
                var    subpaths   = selectedPaths.Where(p => p.StartsWith(pathMarker, StringComparison.Ordinal)).Select(p => p.Substring(pathMarker.Length));

                var value = instance.GetValue(propertyName);
                ExceptionUtilities.CheckObjectNotNull(value, "Value for property '{0}' was null", propertyName);

                if (selectedPaths.Contains(Uri.EscapeDataString(propertyName)))
                {
                    continue;
                }
                else if (subpaths.Any())
                {
                    var maskedValue = this.VisitEntityValues(value, s => this.FixupPropertiesForSelect(s, subpaths));
                    masked.SetValue(propertyName, maskedValue);
                }
                else if (wildCard)
                {
                    masked.SetValue(propertyName, value.Type.NullValue);
                }
                else
                {
                    masked.HideMember(propertyName);
                }
            }

            return(masked);
        }
Esempio n. 5
0
        /// <summary>
        /// Fixes up the properties of the structural value based on the given expanded paths
        /// </summary>
        /// <param name="instance">The value to fix up</param>
        /// <param name="expandedPaths">The expanded paths for the value's scope</param>
        /// <returns>The fixed-up value</returns>
        private QueryStructuralValue FixupPropertiesForExpand(QueryStructuralValue instance, IEnumerable <string> expandedPaths)
        {
            ExceptionUtilities.CheckArgumentNotNull(instance, "instance");
            ExceptionUtilities.CheckArgumentNotNull(expandedPaths, "expandedPaths");

            var entityType = instance.Type as QueryEntityType;

            ExceptionUtilities.CheckObjectNotNull(entityType, "Expand is not supported on non-entity types");

            var masked = MaskedQueryStructuralValue.Create(instance);

            foreach (var navigation in entityType.EntityType.AllNavigationProperties)
            {
                string expandedPath;
                string propertyName = navigation.Name;
                var    value        = instance.GetValue(propertyName);

                ExceptionUtilities.CheckObjectNotNull(value, "Value for property '{0}' was null", propertyName);

                bool   match      = TryGetExpandedPath(expandedPaths, propertyName, entityType.EntityType, out expandedPath);
                string pathMarker = expandedPath + "/";
                var    subpaths   = expandedPaths.Where(p => p.StartsWith(pathMarker, StringComparison.Ordinal)).Select(p => p.Substring(pathMarker.Length));

                // note that if there is match, we still need to fix up up any children, even if there are no subpaths
                if (subpaths.Any() || match)
                {
                    // recurse
                    var maskedValue = this.VisitEntityValues(value, s => this.FixupPropertiesForExpand(s, subpaths));

                    // handle page limit on expanded collections
                    if (maskedValue.Type is QueryCollectionType)
                    {
                        var collection = maskedValue as QueryCollectionValue;
                        ExceptionUtilities.CheckObjectNotNull(collection, "Value was a collection type, but not a collection value");

                        var relatedSet         = entityType.EntitySet.GetRelatedEntitySet(navigation);
                        var relatedSetPageSize = relatedSet.GetEffectivePageSize();
                        if (relatedSetPageSize.HasValue && this.applyPagingInExpands)
                        {
                            collection  = this.AddOrderingForPagingToQueryCollectionValue(collection);
                            maskedValue = collection.Take(relatedSetPageSize.Value);
                        }
                    }

                    masked.SetValue(propertyName, maskedValue);
                }
                else if (!match)
                {
                    // set any non-expanded navigation properties to null
                    masked.SetValue(propertyName, value.Type.NullValue);
                }
            }

            return(masked);
        }
Esempio n. 6
0
        private ComparisonResult CompareGroupingItem <TKey, TElement>(QueryStructuralValue expected, object actual, string path, bool shouldThrow)
        {
            var groupingInterface = (IGrouping <TKey, TElement>)actual;

            QueryValue expectedKey = expected.GetValue("Key");
            var        keysMatch   = this.Compare(expectedKey, groupingInterface.Key, path, false);

            if (keysMatch == ComparisonResult.Success)
            {
                var expectedElements = (QueryCollectionValue)expected.GetValue("Elements");

                return(this.Compare(expectedElements, groupingInterface.Select(e => e), path, shouldThrow));
            }
            else
            {
                this.ThrowOrLogError(shouldThrow, "Grouping keys don't match in '{0}'. Expected: {1}. Actual: {2}.", path, expectedKey, groupingInterface.Key);

                return(ComparisonResult.Failure);
            }
        }
Esempio n. 7
0
        private static void MarkPropertyAsDynamic(QueryStructuralValue value, string memberName)
        {
            var propertyValue = value.GetValue(memberName);

            if (propertyValue.Type is QueryComplexType)
            {
                MarkDynamicSubPropertyValues((QueryStructuralValue)propertyValue);
            }

            propertyValue.AsDynamicPropertyValue();
        }
Esempio n. 8
0
 private void PopulateNonNavigationPropertiesOfVisibleEntity(QueryStructuralValue originalEntity, QueryStructuralValue visibleEntity)
 {
     foreach (var property in originalEntity.Type.Properties)
     {
         bool isCollectionOfNonEntities = property.PropertyType is QueryCollectionType && !(((QueryCollectionType)property.PropertyType).ElementType is QueryEntityType);
         if (property.PropertyType is QueryScalarType || property.PropertyType is QueryComplexType || isCollectionOfNonEntities)
         {
             visibleEntity.SetValue(property.Name, originalEntity.GetValue(property.Name));
         }
     }
 }
        /// <summary>
        /// Static method for creating masked structural values. Will not hide any properties initially.
        /// </summary>
        /// <param name="toMask">The structural value to mask</param>
        /// <returns>A masked structural value</returns>
        internal static MaskedQueryStructuralValue Create(QueryStructuralValue toMask)
        {
            ExceptionUtilities.CheckArgumentNotNull(toMask, "toMask");
            var masked = new MaskedQueryStructuralValue(toMask.Type, toMask.IsNull, toMask.EvaluationError, toMask.Type.EvaluationStrategy);
            foreach (var memberName in toMask.MemberNames)
            {
                masked.SetValue(memberName, toMask.GetValue(memberName));
            }

            masked.Annotations.AddRange(toMask.Annotations.Select(a => a.Clone()));

            return masked;
        }
        /// <summary>
        /// Static method for creating masked structural values. Will not hide any properties initially.
        /// </summary>
        /// <param name="toMask">The structural value to mask</param>
        /// <returns>A masked structural value</returns>
        internal static MaskedQueryStructuralValue Create(QueryStructuralValue toMask)
        {
            ExceptionUtilities.CheckArgumentNotNull(toMask, "toMask");
            var masked = new MaskedQueryStructuralValue(toMask.Type, toMask.IsNull, toMask.EvaluationError, toMask.Type.EvaluationStrategy);

            foreach (var memberName in toMask.MemberNames)
            {
                masked.SetValue(memberName, toMask.GetValue(memberName));
            }

            masked.Annotations.AddRange(toMask.Annotations.Select(a => a.Clone()));

            return(masked);
        }
Esempio n. 11
0
        private void UpdateVisibleEntitiesGraphForAnonymousAndGrouping(QueryStructuralValue anonymousOrGroupingValue, string[] spanPaths)
        {
            // we never take Includes into account for anonymous and grouping properties, hence we can terminate/corrupt the current span path
            string newPath = "[anonymous or grouping]";

            if (!anonymousOrGroupingValue.IsNull)
            {
                foreach (QueryProperty property in anonymousOrGroupingValue.Type.Properties)
                {
                    var originalValue = anonymousOrGroupingValue.GetValue(property.Name);
                    this.UpdateVisibleEntitiesGraphForQueryValue(originalValue, newPath, spanPaths);
                }
            }
        }
 /// <summary>
 /// Creates a copy of the given value recursively
 /// </summary>
 /// <param name="value">The value to copy</param>
 /// <returns>The copied value</returns>
 public QueryValue Visit(QueryStructuralValue value)
 {
     return(this.HandleCommonCasesAndCache(
                value,
                () => value.Type.CreateNewInstance(),
                copy =>
     {
         foreach (var memberName in value.MemberNames)
         {
             var memberValue = value.GetValue(memberName);
             var memberValueCopy = memberValue.Accept(this);
             ((QueryStructuralValue)copy).SetValue(memberName, memberValueCopy);
         }
     }));
 }
Esempio n. 13
0
        /// <summary>
        /// Compares properties of a structural object with expected value. Overridden here to handle named streams.
        /// </summary>
        /// <param name="structuralValue">The structural object containing the property to compare</param>
        /// <param name="expectedName">The name of the property to compare</param>
        /// <param name="expectedPropertyType">The expected type of the property</param>
        /// <param name="actualValue">The actual value of the property</param>
        /// <param name="path">The path to the compared object (for debugging purposes)</param>
        /// <param name="shouldThrow">Should exception be thrown if error is encountered</param>
        /// <returns>The comparison result</returns>
        protected override ComparisonResult CompareProperty(QueryStructuralValue structuralValue, string expectedName, QueryType expectedPropertyType, object actualValue, string path, bool shouldThrow)
        {
            if (this.CodeGenerator.GetType() == typeof(RemoteClientCodeLayerGenerator))
            {
                if (structuralValue.GetValue(expectedName).IsNull&& expectedPropertyType is QueryComplexType)
                {
                    return(ComparisonResult.Success);
                }
            }

            if (expectedPropertyType is AstoriaQueryStreamType)
            {
#if WINDOWS_PHONE
                return(ComparisonResult.Success);
#else
                DataServiceStreamLink   actualStreamLink    = (DataServiceStreamLink)actualValue;
                AstoriaQueryStreamValue expectedStreamValue = (AstoriaQueryStreamValue)structuralValue.GetStreamValue(expectedName);

                if (actualStreamLink == null)
                {
                    if (!expectedStreamValue.IsNull)
                    {
                        this.ThrowOrLogError(shouldThrow, "Expected DataServiceStreamLink property to be null. Actual: {0}", actualStreamLink);
                        return(ComparisonResult.Failure);
                    }
                    else
                    {
                        return(ComparisonResult.Success);
                    }
                }

                try
                {
                    this.VerifyStreamLink(expectedStreamValue, actualStreamLink);
                    return(ComparisonResult.Success);
                }
                catch (TestFailedException e)
                {
                    this.ThrowOrLogError(shouldThrow, e.ToString());
                    return(ComparisonResult.Failure);
                }
#endif
            }
            else
            {
                return(base.CompareProperty(structuralValue, expectedName, expectedPropertyType, actualValue, path, shouldThrow));
            }
        }
Esempio n. 14
0
        /// <summary>
        /// Gets the expected query value for the action request
        /// </summary>
        /// <param name="initialExpectedResults">Initial expected values for an action</param>
        /// <param name="parameterValues">Parameter values for the action</param>
        /// <returns>A query Value that is the expected value</returns>
        public QueryValue GetExpectedQueryValue(QueryValue initialExpectedResults, params QueryValue[] parameterValues)
        {
            ExceptionUtilities.CheckArgumentNotNull(initialExpectedResults, "initialExpectedResults");
            if (initialExpectedResults.IsNull || this.ReturnProperty == null)
            {
                return(initialExpectedResults.Type.NullValue);
            }

            QueryStructuralValue initialStructuralValue = initialExpectedResults as QueryStructuralValue;
            QueryCollectionValue initialCollectionValue = initialExpectedResults as QueryCollectionValue;

            if (initialStructuralValue != null)
            {
                return(initialStructuralValue.GetValue(this.ReturnProperty));
            }
            else
            {
                ExceptionUtilities.CheckArgumentNotNull(initialCollectionValue, "Unsupported initialExpectedResults type.");
                if (initialCollectionValue.Elements.Count > 0)
                {
                    // Sort the results by the keys
                    var queryEntityType = (QueryEntityType)initialCollectionValue.Type.ElementType;
                    var sortedList      = initialCollectionValue.Elements.Select(r => (QueryStructuralValue)r).ToList();
                    foreach (var key in queryEntityType.EntityType.AllKeyProperties)
                    {
                        sortedList = sortedList.OrderBy(r => r.GetScalarValue(key.Name).Value).ToList();
                    }

                    var firstItemValue = (QueryStructuralValue)sortedList.First();
                    ExceptionUtilities.CheckArgumentNotNull(firstItemValue, "firstItemValue");
                    return(firstItemValue.GetValue(this.ReturnProperty));
                }
                else
                {
                    return(initialCollectionValue.Type.ElementType.NullValue);
                }
            }
        }
Esempio n. 15
0
            /// <summary>
            /// Visits the given QueryValue
            /// </summary>
            /// <param name="value">QueryValue being visited.</param>
            /// <returns>The result of visiting this QueryValue.</returns>
            public QueryValue Visit(QueryStructuralValue value)
            {
                if (value.Type is QueryComplexType)
                {
                    return(value);
                }

                if (value.Type is QueryEntityType)
                {
                    return(this.visibleEntitiesGraph[value]);
                }

                var result = value.Type.CreateNewInstance();

                foreach (var property in value.Type.Properties)
                {
                    var propertyValue       = value.GetValue(property.Name);
                    var resultPropertyValue = this.ProcessResult(propertyValue);
                    result.SetValue(property.Name, resultPropertyValue);
                }

                return(result);
            }
Esempio n. 16
0
        /// <summary>
        /// Fixes up the properties of the structural value based on the given selected paths
        /// </summary>
        /// <param name="instance">The value to fix up</param>
        /// <param name="selectedPaths">The selected paths for the value's scope</param>
        /// <returns>The fixed-up value</returns>
        private QueryStructuralValue FixupPropertiesForSelect(QueryStructuralValue instance, IEnumerable<string> selectedPaths)
        {
            ExceptionUtilities.CheckArgumentNotNull(instance, "instance");
            ExceptionUtilities.CheckCollectionNotEmpty(selectedPaths, "selectedPaths");

            var entityType = instance.Type as QueryEntityType;
            ExceptionUtilities.CheckObjectNotNull(entityType, "Select is not supported on non-entity types");

            var masked = MaskedQueryStructuralValue.Create(instance);

            bool wildCard = selectedPaths.Contains(Endpoints.SelectAll);

            var propertyNames = entityType.EntityType.AllProperties.Select(p => p.Name).Concat(entityType.Properties.Streams().Select(m => m.Name));
            foreach (string propertyName in propertyNames)
            {
                if (!selectedPaths.Contains(Uri.EscapeDataString(propertyName)) && !wildCard)
                {
                    // Primitive, bag and stream properties are either entirely present or entirely missing.
                    // However, complex properties can be partially present if a mapped sub-property has a
                    // null value. For this reason, we recursively hide the property and all sub-properties.
                    HidePropertyRecursive(masked, propertyName);
                }
            }

            foreach (string propertyName in entityType.EntityType.AllNavigationProperties.Select(p => p.Name))
            {
                string pathMarker = Uri.EscapeDataString(propertyName) + "/";
                var subpaths = selectedPaths.Where(p => p.StartsWith(pathMarker, StringComparison.Ordinal)).Select(p => p.Substring(pathMarker.Length));

                var value = instance.GetValue(propertyName);
                ExceptionUtilities.CheckObjectNotNull(value, "Value for property '{0}' was null", propertyName);

                if (selectedPaths.Contains(Uri.EscapeDataString(propertyName)))
                {
                    continue;
                }
                else if (subpaths.Any())
                {
                    var maskedValue = this.VisitEntityValues(value, s => this.FixupPropertiesForSelect(s, subpaths));
                    masked.SetValue(propertyName, maskedValue);
                }
                else if (wildCard)
                {
                    masked.SetValue(propertyName, value.Type.NullValue);
                }
                else
                {
                    masked.HideMember(propertyName);
                }
            }

            return masked;
        }
        private void CompareValues(QueryStructuralValue instance, IEnumerable<NamedValue> namedValues, string propertyPath)
        {
            foreach (QueryProperty property in instance.Type.Properties)
            {
                string childPropertyPath = property.Name;
                if (propertyPath != null)
                {
                    childPropertyPath = propertyPath + "." + property.Name;
                }

                // Skip if its an EntityType, this only handles structural types
                var queryEntityType = property.PropertyType as QueryEntityType;
                if (queryEntityType != null)
                {
                    continue;
                }

                var collectionType = property.PropertyType as QueryCollectionType;
                var scalarType = property.PropertyType as QueryScalarType;
                var complexDataType = property.PropertyType as QueryComplexType;

                QueryEntityType collectionQueryElementType = null;
                if (collectionType != null)
                {
                    collectionQueryElementType = collectionType.ElementType as QueryEntityType;
                }

                // Skip if its a collection of QueryEntityType
                if (collectionQueryElementType != null)
                {
                    continue;
                }

                if (scalarType != null)
                {
                    // The following code block handles the case where the value is server generated.
                    // For instance, server generated Keys would fail so if a property is marked as being server generated
                    // we make sure to remove that property from the list of properties to verify
                    MemberProperty memberProperty;
                    var instanceEntityType = instance.Type as QueryEntityType;
                    if (instanceEntityType != null)
                    {
                        memberProperty = instanceEntityType.EntityType.AllProperties.SingleOrDefault(p => p.Name == property.Name);
                    }
                    else
                    {
                        memberProperty = ((QueryComplexType)instance.Type).ComplexType.Properties.SingleOrDefault(p => p.Name == property.Name);
                    }

                    if (memberProperty != null && memberProperty.Annotations.OfType<StoreGeneratedPatternAnnotation>().Any())
                    {
                        // TODO: be more fine-grained about whether this is an update or insert (ie, look at the annotation's property values)
                        this.unusedNamedValuePaths.Remove(childPropertyPath);
                        continue;
                    }

                    NamedValue primitivePropertyNamedValue = namedValues.SingleOrDefault(nv => nv.Name == childPropertyPath);
                    if (primitivePropertyNamedValue != null)
                    {
                        var queryValue = instance.GetScalarValue(property.Name);
                        this.WriteErrorIfNotEqual(childPropertyPath, primitivePropertyNamedValue.Value, queryValue);
                        this.unusedNamedValuePaths.Remove(childPropertyPath);
                    }
                }
                else if (collectionType != null)
                {
                    List<NamedValue> bagNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList();
                    if (bagNamedValues.Any())
                    {
                        this.CompareBagProperty(instance, property, collectionType.ElementType, childPropertyPath, bagNamedValues);
                    }
                    else
                    {
                        this.CompareBagPropertyWithNullOrEmpty(instance, property, childPropertyPath, namedValues);
                    }
                }
                else if (complexDataType != null)
                {
                    // NOTE: we cannot assert that it is complex/primitive/bag, because there may be new query types added in other assemblies that we know nothing about here
                    QueryStructuralValue complexTypeValue = instance.GetStructuralValue(property.Name);

                    List<NamedValue> complexInstanceNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList();
                    if (complexInstanceNamedValues.Any())
                    {
                        if (!this.WriteErrorIfNull(childPropertyPath, complexTypeValue))
                        {
                            this.CompareValues(complexTypeValue, complexInstanceNamedValues, childPropertyPath);
                        }
                    }
                    else
                    {
                        // Check for null case
                        List<NamedValue> exactMatches = namedValues.Where(nv => nv.Name == childPropertyPath).ToList();
                        ExceptionUtilities.Assert(exactMatches.Count < 2, "Should only find at most one property path {0} when looking for null value", childPropertyPath);
                        if (exactMatches.Count == 1)
                        {
                            ExceptionUtilities.Assert(
                                exactMatches[0].Value == null,
                                "Named value at path '{0}' was unexpectedly non-null. Value was '{1}'",
                                childPropertyPath,
                                exactMatches[0].Value);

                            QueryValue queryValue = instance.GetValue(property.Name);
                            this.WriteErrorIfNotNull(childPropertyPath, queryValue);
                            this.unusedNamedValuePaths.Remove(childPropertyPath);
                        }
                    }
                }
            }
        }
Esempio n. 18
0
 /// <summary>
 /// Returns the stream property values for the given entity instance
 /// </summary>
 /// <param name="instance">The instance to get stream property values from</param>
 /// <param name="namedStream">The named stream.</param>
 /// <returns>The stream values of the given instance</returns>
 public static AstoriaQueryStreamValue GetStreamValue(this QueryStructuralValue instance, string namedStream)
 {
     ExceptionUtilities.CheckArgumentNotNull(instance, "instance");
     ExceptionUtilities.CheckArgumentNotNull(namedStream, "namedStream");
     return((AstoriaQueryStreamValue)instance.GetValue(namedStream));
 }
Esempio n. 19
0
        private void CompareValues(QueryStructuralValue instance, IEnumerable <NamedValue> namedValues, string propertyPath)
        {
            foreach (QueryProperty property in instance.Type.Properties)
            {
                string childPropertyPath = property.Name;
                if (propertyPath != null)
                {
                    childPropertyPath = propertyPath + "." + property.Name;
                }

                // Skip if its an EntityType, this only handles structural types
                var queryEntityType = property.PropertyType as QueryEntityType;
                if (queryEntityType != null)
                {
                    continue;
                }

                var collectionType  = property.PropertyType as QueryCollectionType;
                var scalarType      = property.PropertyType as QueryScalarType;
                var complexDataType = property.PropertyType as QueryComplexType;

                QueryEntityType collectionQueryElementType = null;
                if (collectionType != null)
                {
                    collectionQueryElementType = collectionType.ElementType as QueryEntityType;
                }

                // Skip if its a collection of QueryEntityType
                if (collectionQueryElementType != null)
                {
                    continue;
                }

                if (scalarType != null)
                {
                    // The following code block handles the case where the value is server generated.
                    // For instance, server generated Keys would fail so if a property is marked as being server generated
                    // we make sure to remove that property from the list of properties to verify
                    MemberProperty memberProperty;
                    var            instanceEntityType = instance.Type as QueryEntityType;
                    if (instanceEntityType != null)
                    {
                        memberProperty = instanceEntityType.EntityType.AllProperties.SingleOrDefault(p => p.Name == property.Name);
                    }
                    else
                    {
                        memberProperty = ((QueryComplexType)instance.Type).ComplexType.Properties.SingleOrDefault(p => p.Name == property.Name);
                    }

                    if (memberProperty != null && memberProperty.Annotations.OfType <StoreGeneratedPatternAnnotation>().Any())
                    {
                        // TODO: be more fine-grained about whether this is an update or insert (ie, look at the annotation's property values)
                        this.unusedNamedValuePaths.Remove(childPropertyPath);
                        continue;
                    }

                    NamedValue primitivePropertyNamedValue = namedValues.SingleOrDefault(nv => nv.Name == childPropertyPath);
                    if (primitivePropertyNamedValue != null)
                    {
                        var queryValue = instance.GetScalarValue(property.Name);
                        this.WriteErrorIfNotEqual(childPropertyPath, primitivePropertyNamedValue.Value, queryValue);
                        this.unusedNamedValuePaths.Remove(childPropertyPath);
                    }
                }
                else if (collectionType != null)
                {
                    List <NamedValue> bagNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList();
                    if (bagNamedValues.Any())
                    {
                        this.CompareBagProperty(instance, property, collectionType.ElementType, childPropertyPath, bagNamedValues);
                    }
                    else
                    {
                        this.CompareBagPropertyWithNullOrEmpty(instance, property, childPropertyPath, namedValues);
                    }
                }
                else if (complexDataType != null)
                {
                    // NOTE: we cannot assert that it is complex/primitive/bag, because there may be new query types added in other assemblies that we know nothing about here
                    QueryStructuralValue complexTypeValue = instance.GetStructuralValue(property.Name);

                    List <NamedValue> complexInstanceNamedValues = namedValues.Where(nv => nv.Name.StartsWith(childPropertyPath + ".", StringComparison.Ordinal)).ToList();
                    if (complexInstanceNamedValues.Any())
                    {
                        if (!this.WriteErrorIfNull(childPropertyPath, complexTypeValue))
                        {
                            this.CompareValues(complexTypeValue, complexInstanceNamedValues, childPropertyPath);
                        }
                    }
                    else
                    {
                        // Check for null case
                        List <NamedValue> exactMatches = namedValues.Where(nv => nv.Name == childPropertyPath).ToList();
                        ExceptionUtilities.Assert(exactMatches.Count < 2, "Should only find at most one property path {0} when looking for null value", childPropertyPath);
                        if (exactMatches.Count == 1)
                        {
                            ExceptionUtilities.Assert(
                                exactMatches[0].Value == null,
                                "Named value at path '{0}' was unexpectedly non-null. Value was '{1}'",
                                childPropertyPath,
                                exactMatches[0].Value);

                            QueryValue queryValue = instance.GetValue(property.Name);
                            this.WriteErrorIfNotNull(childPropertyPath, queryValue);
                            this.unusedNamedValuePaths.Remove(childPropertyPath);
                        }
                    }
                }
            }
        }
            private void VisitStructuralInstance(ComplexInstance payloadElement, QueryStructuralValue value)
            {
                ExceptionUtilities.CheckArgumentNotNull(payloadElement, "payloadElement");
                ExceptionUtilities.CheckArgumentNotNull(value, "value");

                var entityType = value.Type as QueryEntityType;
                var complexType = value.Type as QueryComplexType;
                ExceptionUtilities.Assert(entityType != null || complexType != null, "Value was neither an entity type nor a complex type");

                bool isEntity = entityType != null;
                string errorType = isEntity ? "Entity" : "Complex";

                if (value.IsNull)
                {
                    this.parent.Assert.IsTrue(payloadElement.IsNull, errorType + " instance unexpectedly non-null");
                    return;
                }
                else
                {
                    this.parent.Assert.IsFalse(payloadElement.IsNull, errorType + " instance unexpectedly null");

                    this.VerifyTypeName(value, payloadElement.FullTypeName, errorType + " instance type name did not match expectation.");
                }

                // get all the payload properties, and remove them as we go to detect any extras
                var payloadProperties = payloadElement.Properties.ToList();

                // this is data-driven to deal with open types, but we need to skip over the 'default stream' property if it exists
                foreach (var propertyName in value.MemberNames.Where(m => m != AstoriaQueryStreamType.DefaultStreamPropertyName))
                {
                    var propertyInstance = payloadProperties.SingleOrDefault(p => p.Name == propertyName);
                    this.parent.Assert.IsNotNull(propertyInstance, string.Format(CultureInfo.InvariantCulture, "Could not find property '{0}' in payload", propertyName));
                    payloadProperties.Remove(propertyInstance);

                    var propertyValue = value.GetValue(propertyName);
                    this.RecurseWithMessage(propertyInstance, propertyValue, "{0} instance did not match expectation", errorType);
                }

                string extraPropertyNames = string.Join(", ", payloadProperties.Select(p => '\'' + p.Name + '\'').ToArray());
                this.parent.Assert.IsTrue(payloadProperties.Count == 0, string.Format(CultureInfo.InvariantCulture, "{0} instance contained unexpected properties: {1}", errorType, extraPropertyNames));
            }
Esempio n. 21
0
        /// <summary>
        /// Compares a property of a structural object with expected value
        /// </summary>
        /// <param name="structuralValue">The structural object containing the property to compare</param>
        /// <param name="expectedName">The name of the property to compare</param>
        /// <param name="expectedPropertyType">The expected type of the property</param>
        /// <param name="actualValue">The actual value of the property</param>
        /// <param name="path">The path to the compared object (for debugging purposes)</param>
        /// <param name="shouldThrow">Should exception be thrown if error is encountered</param>
        /// <returns>Result of the comparison</returns>
        protected virtual ComparisonResult CompareProperty(QueryStructuralValue structuralValue, string expectedName, QueryType expectedPropertyType, object actualValue, string path, bool shouldThrow)
        {
            var expectedPropertyValue = structuralValue.GetValue(expectedName);

            return(this.Compare(expectedPropertyValue, actualValue, path, shouldThrow));
        }
Esempio n. 22
0
        /// <summary>
        /// Fixes up the properties of the structural value based on the given expanded paths
        /// </summary>
        /// <param name="instance">The value to fix up</param>
        /// <param name="expandedPaths">The expanded paths for the value's scope</param>
        /// <returns>The fixed-up value</returns>
        private QueryStructuralValue FixupPropertiesForExpand(QueryStructuralValue instance, IEnumerable<string> expandedPaths)
        {
            ExceptionUtilities.CheckArgumentNotNull(instance, "instance");
            ExceptionUtilities.CheckArgumentNotNull(expandedPaths, "expandedPaths");

            var entityType = instance.Type as QueryEntityType;
            ExceptionUtilities.CheckObjectNotNull(entityType, "Expand is not supported on non-entity types");

            var masked = MaskedQueryStructuralValue.Create(instance);

            foreach (var navigation in entityType.EntityType.AllNavigationProperties)
            {
                string expandedPath;
                string propertyName = navigation.Name;
                var value = instance.GetValue(propertyName);
                
                ExceptionUtilities.CheckObjectNotNull(value, "Value for property '{0}' was null", propertyName);

                bool match = TryGetExpandedPath(expandedPaths, propertyName, entityType.EntityType, out expandedPath);
                string pathMarker = expandedPath + "/";
                var subpaths = expandedPaths.Where(p => p.StartsWith(pathMarker, StringComparison.Ordinal)).Select(p => p.Substring(pathMarker.Length));

                // note that if there is match, we still need to fix up up any children, even if there are no subpaths
                if (subpaths.Any() || match)
                {
                    // recurse
                    var maskedValue = this.VisitEntityValues(value, s => this.FixupPropertiesForExpand(s, subpaths));

                    // handle page limit on expanded collections
                    if (maskedValue.Type is QueryCollectionType)
                    {
                        var collection = maskedValue as QueryCollectionValue;
                        ExceptionUtilities.CheckObjectNotNull(collection, "Value was a collection type, but not a collection value");

                        var relatedSet = entityType.EntitySet.GetRelatedEntitySet(navigation);
                        var relatedSetPageSize = relatedSet.GetEffectivePageSize();
                        if (relatedSetPageSize.HasValue && this.applyPagingInExpands)
                        {
                            collection = this.AddOrderingForPagingToQueryCollectionValue(collection);
                            maskedValue = collection.Take(relatedSetPageSize.Value);
                        }
                    }

                    masked.SetValue(propertyName, maskedValue);
                }
                else if (!match)
                {
                    // set any non-expanded navigation properties to null
                    masked.SetValue(propertyName, value.Type.NullValue);
                }
            }

            return masked;
        }