/// <summary> /// Determines whether a typed data can do certain operation with another typed data /// </summary> /// <param name="operation">the operation</param> /// <param name="sourceType">the type of data to operation on</param> /// <param name="otherType">the other type</param> /// <returns>Value <c>true</c> if operation can be performed; otherwise, <c>false</c>.</returns> public override bool Supports(QueryBinaryOperation operation, QueryScalarType sourceType, QueryScalarType otherType) { if (this.IsSpatialType((IQueryClrType)sourceType) || this.IsSpatialType((IQueryClrType)otherType)) { return(false); } return(base.Supports(operation, sourceType, otherType)); }
/// <summary> /// Determines whether a typed data can do certain operation with another typed data /// </summary> /// <param name="operation">the operation</param> /// <param name="sourceType">the type of data to operation on</param> /// <param name="otherType">the other type</param> /// <returns>Value <c>true</c> if operation can be performed; otherwise, <c>false</c>.</returns> public virtual bool Supports(QueryBinaryOperation operation, QueryScalarType sourceType, QueryScalarType otherType) { var sourceQueryClrType = (IQueryClrType)sourceType; var otherQueryClrType = (IQueryClrType)otherType; var sourceClrType = sourceQueryClrType.ClrType; var otherClrType = otherQueryClrType.ClrType; switch (operation) { case QueryBinaryOperation.Add: case QueryBinaryOperation.Divide: case QueryBinaryOperation.Modulo: case QueryBinaryOperation.Multiply: case QueryBinaryOperation.Subtract: return(LinqTypeSemantics.IsNumeric(sourceClrType) && LinqTypeSemantics.IsNumeric(otherClrType) && this.HaveCommonType(sourceClrType, otherClrType)); case QueryBinaryOperation.BitwiseAnd: case QueryBinaryOperation.BitwiseExclusiveOr: case QueryBinaryOperation.BitwiseOr: return(LinqTypeSemantics.IsIntegralType(sourceClrType) && LinqTypeSemantics.IsIntegralType(otherClrType) && this.HaveCommonType(sourceClrType, otherClrType)); case QueryBinaryOperation.LogicalAnd: case QueryBinaryOperation.LogicalOr: return(sourceClrType == typeof(bool) && otherClrType == typeof(bool)); case QueryBinaryOperation.EqualTo: case QueryBinaryOperation.NotEqualTo: return(this.HaveCommonType(sourceClrType, otherClrType)); case QueryBinaryOperation.LessThan: case QueryBinaryOperation.LessThanOrEqualTo: case QueryBinaryOperation.GreaterThan: case QueryBinaryOperation.GreaterThanOrEqualTo: if (sourceClrType == typeof(byte[]) || otherClrType == typeof(byte[]) || sourceClrType == typeof(string) || otherClrType == typeof(string) || sourceClrType == typeof(bool) || otherClrType == typeof(bool) || sourceClrType == typeof(bool?) || otherClrType == typeof(bool?) || this.IsSpatialType(sourceQueryClrType) || this.IsSpatialType(otherQueryClrType)) { return(false); } else { return(this.HaveCommonType(sourceClrType, otherClrType)); } case QueryBinaryOperation.Concat: return(sourceClrType == typeof(string) || otherClrType == typeof(string)); default: throw new TaupoNotSupportedException("Unsupported query binary operation."); } }
/// <summary> /// Determines whether a typed data can do certain operation /// </summary> /// <param name="operation">the operation</param> /// <param name="sourceType">the type of data to operate on</param> /// <returns>Value <c>true</c> if operation can be performed; otherwise, <c>false</c>.</returns> public bool Supports(QueryUnaryOperation operation, QueryScalarType sourceType) { switch (operation) { case QueryUnaryOperation.LogicalNegate: return(((IQueryClrType)sourceType).ClrType == typeof(bool)); default: throw new TaupoNotSupportedException("Unsupported query unary operation."); } }
/// <summary> /// Factory method to create the <see cref="QueryConstantExpression"/>. /// </summary> /// <param name="value">Value of the expression.</param> /// <param name="valueType">Type of the expression.</param> /// <returns>The <see cref="QueryConstantExpression"/> with the provided arguments.</returns> public static QueryConstantExpression Constant(object value, QueryScalarType valueType) { ExceptionUtilities.CheckArgumentNotNull(valueType, "valueType"); if (value == null) { ExceptionUtilities.Assert(!valueType.IsUnresolved, "When value is null type cannot be unresolved."); } return(Constant(valueType.CreateValue(value))); }
/// <summary> /// Determines whether a type supports ordering. /// </summary> /// <param name="sourceType">the type of data to operation on</param> /// <returns>Value <c>true</c> if ordering can be performed; otherwise, <c>false</c>.</returns> public bool SupportsOrderComparison(QueryScalarType sourceType) { // Ordering is supported for all primitive types in the clr // Note, this is ordering in the sense of "orderby p.ProductName", not Where(p => p.ProductName < "foo" ). var spatialType = sourceType as QueryClrSpatialType; if (spatialType != null) { return(false); } return(true); }
/// <summary> /// Casts a <see cref="QueryScalarValue"/> to a <see cref="QueryScalarType"/>. The cast will return the value type cast to the new type. /// </summary> /// <param name="source">The source for the cast operation.</param> /// <param name="type">The type for the cast operation.</param> /// <returns><see cref="QueryScalarValue"/> which is cast to the appropriate type</returns> public QueryScalarValue Cast(QueryScalarValue source, QueryScalarType type) { var targetType = (QueryClrPrimitiveType)type; try { return(this.EvaluateCast(source.Value, targetType)); } catch (InvalidCastException) { return(targetType.CreateValue(null)); } }
/// <summary> /// Evaluates the property. /// </summary> /// <param name="resultType">Type of the result.</param> /// <param name="propertyName">Name of the property.</param> /// <param name="instance">The instance.</param> /// <returns> /// Query value which is the result of the function evaluation. /// </returns> private QueryValue EvaluateProperty(QueryScalarType resultType, string propertyName, QueryScalarValue instance) { if (instance.Value == null) { // TODO: evaluation error? return(resultType.NullValue); } var type = instance.Value.GetType(); var propertyInfo = type.GetProperty(propertyName); ExceptionUtilities.CheckObjectNotNull(propertyInfo, "Could not find property named '{0}' on '{1}'", propertyName, instance.Value); var value = propertyInfo.GetValue(instance.Value, null); return(resultType.CreateValue(value)); }
private void BuildStructuralPropertiesQueryValue(QueryStructuralValue instance, string propertyPath, IList <MemberProperty> properties, IList <QueryProperty> queryProperties, EntitySetDataRow row) { ExceptionUtilities.Assert(properties.Count == queryProperties.Count, "QueryProperties '{0}' and MemberProperties '{1}' are not the same number!", CreateQueryPropertyList(queryProperties), CreateMemberPropertyList(properties)); // TODO: Some Taupo framework pieces skip over StreamDataType properties foreach (MemberProperty childProperty in properties.Where(p => !(p.PropertyType is StreamDataType))) { string childPropertyPath = propertyPath + childProperty.Name; List <QueryProperty> childQueryProperties = queryProperties.Where(p => p.Name == childProperty.Name).ToList(); ExceptionUtilities.Assert(childQueryProperties.Count == 1, "Could not find query property based on MemberProperty Name '{0}' in list of query properties '{1}'", childProperty.Name, CreateQueryPropertyList(childQueryProperties)); QueryProperty childQueryProperty = childQueryProperties.First(); QueryCollectionType childCollectionDataType = childQueryProperty.PropertyType as QueryCollectionType; QueryScalarType childScalarType = childQueryProperty.PropertyType as QueryScalarType; QueryComplexType childComplexType = childQueryProperty.PropertyType as QueryComplexType; if (childCollectionDataType != null) { instance.SetValue(childProperty.Name, this.BuildCollectionQueryValue(childPropertyPath + ".", childCollectionDataType, row)); } else if (childScalarType != null) { var value = row[childPropertyPath]; var queryValue = childScalarType.CreateValue(value); instance.SetValue(childQueryProperty.Name, queryValue); } else { ExceptionUtilities.CheckObjectNotNull(childComplexType, "Unknown type '{0}'", childProperty.PropertyType); // If a complex type instance is null in the datarow, we will create a QueryStructuralValue indicating null and set it on the instance. if (row.PropertyPaths.Contains(childPropertyPath) && row[childPropertyPath] == null) { instance.SetValue(childProperty.Name, new QueryStructuralValue(childComplexType, true, null, childComplexType.EvaluationStrategy)); } else { QueryStructuralValue childInstance = childComplexType.CreateNewInstance(); this.BuildStructuralPropertiesQueryValue(childInstance, childPropertyPath + ".", childComplexType.ComplexType.Properties, childComplexType.Properties, row); instance.SetValue(childProperty.Name, childInstance); } } } }
/// <summary> /// Compares the given values of the given type, and throws a DataComparisonException or AssertionFailedException if values don't match /// </summary> /// <param name="type">The expected type</param> /// <param name="expected">The expected value</param> /// <param name="actual">The actual value</param> /// <param name="assert">The assertion handler to use</param> protected virtual void Compare(QueryScalarType type, object expected, object actual, AssertionHandler assert) { ExceptionUtilities.CheckArgumentNotNull(type, "type"); ExceptionUtilities.CheckArgumentNotNull(assert, "assert"); if (expected == type.NullValue.Value) { assert.IsNull(actual, "Primitive value unexpectedly non-null"); } else { assert.IsNotNull(actual, "Primitive value unexpectedly null"); assert.AreEqual(expected.GetType(), actual.GetType(), EqualityComparer <Type> .Default, "Types did not match"); var comparer = new DelegateBasedEqualityComparer <QueryScalarValue>((v1, v2) => v1.Type.EvaluationStrategy.Compare(v1, v2) == 0); assert.AreEqual(type.CreateValue(expected), type.CreateValue(actual), comparer, "Primitive value did not match"); } }
/// <summary> /// Build the collection of primitive types which will be set on the constructed repository /// </summary> /// <param name="queryTypeLibrary">Query Type Library to build Types from</param> protected override void BuildPrimitiveTypes(QueryTypeLibrary queryTypeLibrary) { this.intType = (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Int32); this.stringType = (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.String()); this.PrimitiveTypes = new List <QueryScalarType>() { // this is just a sample this.intType, this.stringType, (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Boolean), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.DateTime()), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Decimal()), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Int64), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Int16), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Byte), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Single), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Double), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Binary()), (QueryScalarType)queryTypeLibrary.GetDefaultQueryType(EdmDataTypes.Guid), }; }
/// <summary> /// Factory method to create the <see cref="LinqToAstoriaKeyExpression"/>. /// </summary> /// <param name="source">The source query.</param> /// <param name="keys">The set of key property values.</param> /// <returns>The <see cref="QueryExpression"/> with the provided arguments.</returns> public static LinqToAstoriaKeyExpression Key(this QueryExpression source, IEnumerable <NamedValue> keys) { ExceptionUtilities.CheckArgumentNotNull(source, "source"); ExceptionUtilities.CheckCollectionNotEmpty(keys, "keys"); QueryType elementType = QueryType.Unresolved; var queryCollectionType = source.ExpressionType as QueryCollectionType; if (queryCollectionType != null) { elementType = queryCollectionType.ElementType; } var structuralType = elementType as QueryStructuralType; var key = new List <KeyValuePair <QueryProperty, QueryConstantExpression> >(); foreach (var keyValue in keys) { QueryScalarType primitiveType = QueryType.UnresolvedPrimitive; QueryProperty queryProperty = QueryProperty.Create(keyValue.Name, primitiveType); if (structuralType != null) { queryProperty = structuralType.Properties.SingleOrDefault(p => p.Name == keyValue.Name); ExceptionUtilities.CheckObjectNotNull(queryProperty, "Could not find property with name '{0}' on type '{1}'", keyValue.Name, structuralType); primitiveType = queryProperty.PropertyType as QueryScalarType; ExceptionUtilities.CheckObjectNotNull(primitiveType, "Property '{0}' on type '{1}' was not a primitive type", keyValue.Name, structuralType); } var value = CommonQueryBuilder.Constant(keyValue.Value, primitiveType); key.Add(new KeyValuePair <QueryProperty, QueryConstantExpression>(queryProperty, value)); } return(new LinqToAstoriaKeyExpression(source, key, source.ExpressionType)); }
/// <summary> /// Removes any length constraints from the type /// </summary> /// <param name="type">The type from which to remove the constraints</param> /// <returns>The new type with length constraints removed.</returns> public QueryScalarType RemoveLengthConstraints(QueryScalarType type) { return(type); }
/// <summary> /// Gets the common type to which both types can be promoted. /// </summary> /// <param name="leftType">First type.</param> /// <param name="rightType">Second type.</param> /// <returns> /// Common type to which both types can be promoted. Throws if unable to find a common type. /// </returns> public QueryScalarType GetCommonType(QueryScalarType leftType, QueryScalarType rightType) { Type commonClrType = LinqTypeSemantics.GetCommonType(((QueryClrPrimitiveType)leftType).ClrType, ((QueryClrPrimitiveType)rightType).ClrType); return(new QueryClrPrimitiveType(commonClrType, this)); }
private void UpdateScalarBag(QueryStructuralValue instance, QueryProperty memberProperty, string propertyPath, IEnumerable <NamedValue> namedValues, QueryScalarType scalarElementDataType) { int i = 0; var scalarCollection = new List <QueryValue>(); List <NamedValue> scalarItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); while (scalarItemNamedValues.Any()) { ExceptionUtilities.Assert(scalarItemNamedValues.Count() < 2, "Should not get more than one value for a scalar Bag item for path '{0}'", propertyPath + "." + i); var value = scalarItemNamedValues.Single(); scalarCollection.Add(scalarElementDataType.CreateValue(value.Value)); this.unusedNamedValuePaths.Remove(value.Name); i++; scalarItemNamedValues = namedValues.Where(pp => pp.Name == propertyPath + "." + i).ToList(); } if (scalarCollection.Any()) { this.SetCollectionProperty(instance, memberProperty, scalarCollection); } }
private QueryValue VisitScalar(QueryScalarType queryScalarType) { var scalarResult = this.ResultFragmentStack.Pop(); return(queryScalarType.CreateValue(scalarResult)); }
private void UpdateRootScalarBag(QueryCollectionValue instance, IEnumerable <NamedValue> namedValues, QueryScalarType scalarElementDataType) { int i = 0; var scalarCollection = new List <QueryValue>(); List <NamedValue> scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList(); while (scalarItemNamedValues.Any()) { ExceptionUtilities.Assert(scalarItemNamedValues.Count() < 2, "Should not get more than one value for a scalar Bag item for path '{0}'", i.ToString(CultureInfo.InvariantCulture)); var value = scalarItemNamedValues.Single(); scalarCollection.Add(scalarElementDataType.CreateValue(value.Value)); this.unusedNamedValuePaths.Remove(value.Name); i++; scalarItemNamedValues = namedValues.Where(pp => pp.Name == i.ToString(CultureInfo.InvariantCulture)).ToList(); } if (scalarCollection.Any()) { this.SetCollectionValue(instance, scalarCollection); } }
/// <summary> /// Evaluates the specified expression. /// </summary> /// <param name="expression">The expression to evaluate.</param> /// <returns>Value of the expression.</returns> public virtual QueryValue Visit(QueryCustomFunctionCallExpression expression) { QueryValue result; var argumentValues = this.EvaluateArguments(expression.Arguments); var customEvaluator = expression.Function.Annotations.OfType <FunctionEvaluatorAnnotation>().Select(a => a.FunctionEvaluator).SingleOrDefault(); if (customEvaluator != null) { result = customEvaluator(expression.ExpressionType, argumentValues); } else if (expression.FunctionBody != null) { QueryExpression functionBody = expression.FunctionBody; // replace parameter refs with arguments if (expression.Function.Parameters.Any()) { // Consider query: // "select value DefaultNamespace.GetCustomer(c.CustomerId) from [DefaultContainer].[Customer] as c" where GetCustomer is a function. // After we replace parameter references in the function's body with "c.CustomerId" expression evaluation // of the body expression fails becuase variable "c" is not in the scope for the function's body. // Note also that function body itself can have a variable reference with the same name "c". // So the right thing is to evaluate each argument and then replace parameter references with constant expressions. // However QueryConstantExpression currently only supports QueryScalarType/QueryScalarValue. // So for now we only evaluating scalar arguments. // TODO: add supoort for non-scalar constants and change the following code to evaluate each argument // NOTE: we have similar limitation in LinqToEntitiesEvaluator List <QueryExpression> evaluatedArguments = new List <QueryExpression>(); foreach (var argument in expression.Arguments) { QueryScalarType scalarArgumentType = argument.ExpressionType as QueryScalarType; if (scalarArgumentType != null) { QueryScalarValue scalarValue = (QueryScalarValue)this.Evaluate(argument); var constant = CommonQueryBuilder.Constant(scalarValue); evaluatedArguments.Add(constant); } else { evaluatedArguments.Add(argument); } } var visitor = this.CreateFunctionParameterReferenceReplacingVisitor(expression.Function, evaluatedArguments); functionBody = visitor.ReplaceExpression(expression.FunctionBody); } result = this.Evaluate(functionBody); } else { result = expression.ExpressionType.EvaluationStrategy.EvaluateFunction( expression.ExpressionType, expression.Function, argumentValues); } return(result); }