Skip to content

Commit

Permalink
Improved containvalues handling
Browse files Browse the repository at this point in the history
Fixes #110
  • Loading branch information
MarkMpn committed Aug 17, 2021
1 parent 73be796 commit 90ff29e
Show file tree
Hide file tree
Showing 5 changed files with 113 additions and 7 deletions.
85 changes: 85 additions & 0 deletions MarkMpn.Sql4Cds.Engine.Tests/Sql2FetchXmlTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2103,6 +2103,62 @@ public void CaseInsensitive()
");
}

[TestMethod]
public void ContainsValues1()
{
var context = new XrmFakedContext();
context.InitializeMetadata(Assembly.GetExecutingAssembly());

var org = context.GetOrganizationService();
var metadata = new AttributeMetadataCache(org);
var sql2FetchXml = new Sql2FetchXml(metadata, true);

var query = "SELECT new_name FROM new_customentity WHERE CONTAINS(new_optionsetvaluecollection, '1')";

var queries = sql2FetchXml.Convert(query);

AssertFetchXml(queries, $@"
<fetch>
<entity name='new_customentity'>
<attribute name='new_name' />
<filter>
<condition attribute='new_optionsetvaluecollection' operator='contain-values'>
<value>1</value>
</condition>
</filter>
</entity>
</fetch>
");
}

[TestMethod]
public void ContainsValuesFunction1()
{
var context = new XrmFakedContext();
context.InitializeMetadata(Assembly.GetExecutingAssembly());

var org = context.GetOrganizationService();
var metadata = new AttributeMetadataCache(org);
var sql2FetchXml = new Sql2FetchXml(metadata, true);

var query = "SELECT new_name FROM new_customentity WHERE new_optionsetvaluecollection = containvalues(1)";

var queries = sql2FetchXml.Convert(query);

AssertFetchXml(queries, $@"
<fetch>
<entity name='new_customentity'>
<attribute name='new_name' />
<filter>
<condition attribute='new_optionsetvaluecollection' operator='contain-values'>
<value>1</value>
</condition>
</filter>
</entity>
</fetch>
");
}

[TestMethod]
public void ContainsValues()
{
Expand Down Expand Up @@ -2132,6 +2188,35 @@ public void ContainsValues()
");
}

[TestMethod]
public void ContainsValuesFunction()
{
var context = new XrmFakedContext();
context.InitializeMetadata(Assembly.GetExecutingAssembly());

var org = context.GetOrganizationService();
var metadata = new AttributeMetadataCache(org);
var sql2FetchXml = new Sql2FetchXml(metadata, true);

var query = "SELECT new_name FROM new_customentity WHERE new_optionsetvaluecollection = containvalues(1, 2)";

var queries = sql2FetchXml.Convert(query);

AssertFetchXml(queries, $@"
<fetch>
<entity name='new_customentity'>
<attribute name='new_name' />
<filter>
<condition attribute='new_optionsetvaluecollection' operator='contain-values'>
<value>1</value>
<value>2</value>
</condition>
</filter>
</entity>
</fetch>
");
}

[TestMethod]
public void NotContainsValues()
{
Expand Down
2 changes: 1 addition & 1 deletion MarkMpn.Sql4Cds.Engine/ExecutionPlan/BaseDataNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ private bool TranslateFetchXMLCriteriaWithVirtualAttributes(EntityMetadata meta,
var attrNames = new[] { attrName };
var ft = filterType.and;

var usesItems = values != null && values.Length > 1 || op == @operator.@in || op == @operator.notin;
var usesItems = values != null && values.Length > 1 || op == @operator.@in || op == @operator.notin || op == @operator.containvalues || op == @operator.notcontainvalues;

if (attribute is DateTimeAttributeMetadata && literals != null &&
(op == @operator.eq || op == @operator.ne || op == @operator.neq || op == @operator.gt || op == @operator.ge || op == @operator.lt || op == @operator.le))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,7 @@ private static MethodInfo GetMethod(Type targetType, FunctionCall func, Type[] p
{
var paramType = parameters[i].ParameterType;

if (i == parameters.Length - 1 && paramTypes.Length > parameters.Length && paramType.IsArray)
if (i == parameters.Length - 1 && paramTypes.Length >= parameters.Length && paramType.IsArray)
paramType = paramType.GetElementType();

if (!SqlTypeConverter.CanChangeTypeImplicit(paramTypes[i], paramType))
Expand Down
27 changes: 24 additions & 3 deletions MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using Microsoft.VisualBasic;
using Microsoft.Xrm.Sdk;
using System;
using System.Collections.Generic;
using System.Data.SqlTypes;
using System.Linq;
using System.Linq.Expressions;
Expand Down Expand Up @@ -408,14 +409,34 @@ public static MethodCallExpression Call<T>(Expression<Func<T>> expression, param
public static MethodCallExpression Call(MethodInfo method, params Expression[] args)
{
var parameters = method.GetParameters();
var converted = new Expression[parameters.Length];

for (var i = 0; i < parameters.Length; i++)
{
if (parameters[i].ParameterType != args[i].Type)
args[i] = Convert(args[i], parameters[i].ParameterType);
if (parameters[i].ParameterType == args[i].Type)
{
converted[i] = args[i];
}
else
{
if (i == parameters.Length - 1 && parameters[i].ParameterType.IsArray && !args[i].Type.IsArray)
{
var elementType = parameters[i].ParameterType.GetElementType();
var elements = new List<Expression>();

for (var j = i; j < args.Length; j++)
elements.Add(Convert(args[j], elementType));

converted[i] = Expression.NewArrayInit(elementType, elements.ToArray());
}
else
{
converted[i] = Convert(args[i], parameters[i].ParameterType);
}
}
}

return Expression.Call(method, args);
return Expression.Call(method, converted);
}

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions MarkMpn.Sql4Cds.Engine/FetchXmlConditionMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ public static class FetchXmlConditionMethods
public static SqlBoolean EqOrAbove(SqlGuid field, SqlGuid value) => ThrowException();

[Description("Matches a multi-select picklist value that contains any of the specified values")]
public static SqlBoolean ContainValues(OptionSetValueCollection field, SqlInt32[] value) => ThrowException();
public static SqlBoolean ContainValues(SqlString field, SqlInt32[] value) => ThrowException();

[Description("Matches a multi-select picklist value that doesn't contains any of the specified values")]
public static SqlBoolean NotContainValues(OptionSetValueCollection field, SqlInt32[] value) => ThrowException();
public static SqlBoolean NotContainValues(SqlString field, SqlInt32[] value) => ThrowException();

private static SqlBoolean ThrowException()
{
Expand Down

0 comments on commit 90ff29e

Please sign in to comment.