Skip to content

Commit

Permalink
Added support for scale and precision.
Browse files Browse the repository at this point in the history
Added support for negation of expressions.
  • Loading branch information
glecchi committed Aug 8, 2024
1 parent 722fb81 commit 8c09b07
Show file tree
Hide file tree
Showing 5 changed files with 434 additions and 44 deletions.
2 changes: 1 addition & 1 deletion Lib/CSQLQueryExpress/CSQLQueryExpress.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Title>CSQLQueryExpress</Title>
<Version>1.3.3</Version>
<Version>1.3.4</Version>
<Description>A simple c# library to compile TSQL queries</Description>
<PackageProjectUrl></PackageProjectUrl>
<PackageReadmeFile>README.md</PackageReadmeFile>
Expand Down
253 changes: 210 additions & 43 deletions Lib/CSQLQueryExpress/Compiler/SQLQueryTranslator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml.Linq;

namespace CSQLQueryExpress
{
Expand Down Expand Up @@ -710,6 +711,48 @@ private Expression VisitStringMethodCall(MethodCallExpression node)
throw new NotSupportedException(string.Format("The method '{0}' is not supported.", node.Method.Name));
}

private Expression VisitStringNegationMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(string.StartsWith))
{
_queryBuilder.Append("(");
this.Visit(node.Object);
_queryBuilder.Append(" NOT LIKE ");
var valueExpression = (ConstantExpression)node.Arguments[0];
var parameterName = _parametersBuilder.AddParameter($"{valueExpression.Value}%");
_queryBuilder.Append(parameterName);
_queryBuilder.Append(")");

return node;
}
else if (node.Method.Name == nameof(string.EndsWith))
{
_queryBuilder.Append("(");
this.Visit(node.Object);
_queryBuilder.Append(" NOT LIKE ");
var valueExpression = (ConstantExpression)node.Arguments[0];
var parameterName = _parametersBuilder.AddParameter($"%{valueExpression.Value}");
_queryBuilder.Append(parameterName);
_queryBuilder.Append(")");

return node;
}
else if (node.Method.Name == nameof(string.Contains))
{
_queryBuilder.Append("(");
this.Visit(node.Object);
_queryBuilder.Append(" NOT LIKE ");
var valueExpression = (ConstantExpression)node.Arguments[0];
var parameterName = _parametersBuilder.AddParameter($"%{valueExpression.Value}%");
_queryBuilder.Append(parameterName);
_queryBuilder.Append(")");

return node;
}

throw new NotSupportedException(string.Format("The method '{0}' is not supported.", node.Method.Name));
}

public Expression VisitQueryPaginationMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(SQLQueryPaginationExtensions.Offset))
Expand Down Expand Up @@ -976,6 +1019,21 @@ private Expression VisitQueryDefinitionMethodCall(MethodCallExpression node)

return node;
}
else if (node.Method.Name == nameof(SQLQueryDefinitionExtensions.Precision))
{
this.Visit(node.Arguments[0]);

if (node.Arguments.Count == 1)
{
_queryBuilder.Append($"({((ConstantExpression)node.Arguments[1]).Value})");
}
else
{
_queryBuilder.Append($"({((ConstantExpression)node.Arguments[1]).Value}, {((ConstantExpression)node.Arguments[2]).Value})");
}

return node;
}
if (node.Method.Name == nameof(SQLQueryDefinitionExtensions.Asc))
{
Visit(node.Arguments[0]);
Expand All @@ -998,50 +1056,25 @@ private Expression VisitQueryConditionMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(SQLQueryConditionExtension.IsNull))
{
if (node.Arguments.Count == 1)
{
_queryBuilder.Append("(");
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" IS NULL");
_queryBuilder.Append(")");
}
else
{
_queryBuilder.Append("ISNULL(");
this.Visit(node.Arguments[0]);
_queryBuilder.Append(", ");
this.Visit(node.Arguments[1]);
_queryBuilder.Append(")");
}
TranslateIsNullCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.IsNotNull))
{
_queryBuilder.Append("(");
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" IS NOT NULL");
_queryBuilder.Append(")");
TranslateIsNotNullCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.In))
{
_queryBuilder.Append("(");
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" IN (");
this.Visit(node.Arguments[1]);
_queryBuilder.Append("))");
TranslateInCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotIn))
{
_queryBuilder.Append("(");
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" NOT IN (");
this.Visit(node.Arguments[1]);
_queryBuilder.Append("))");
TranslateNotInCondition(node);

return node;
}
Expand All @@ -1054,42 +1087,161 @@ private Expression VisitQueryConditionMethodCall(MethodCallExpression node)
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.Exists))
{
_queryBuilder.Append("EXISTS ");
this.Visit(node.Arguments[1]);
TranslateExistsCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotExists))
{
_queryBuilder.Append("NOT EXISTS ");
this.Visit(node.Arguments[1]);
TranslateNotExistsCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.Between))
{
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" BETWEEN ");
this.Visit(node.Arguments[1]);
_queryBuilder.Append(" AND ");
this.Visit(node.Arguments[2]);
TranslateBetweenCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotBetween))
{
this.Visit(node.Arguments[0]);
_queryBuilder.Append(" NOT BETWEEN ");
this.Visit(node.Arguments[1]);
_queryBuilder.Append(" AND ");
this.Visit(node.Arguments[2]);
TranslateNotBetweenCondition(node);

return node;
}

throw new NotSupportedException(string.Format("The method '{0}' is not supported.", node.Method.Name));
}

private Expression VisitQueryConditionNegationMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(SQLQueryConditionExtension.IsNull))
{
TranslateIsNotNullCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.IsNotNull))
{
TranslateIsNullCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.In))
{
TranslateNotInCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotIn))
{
TranslateInCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.Exists))
{
TranslateNotExistsCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotExists))
{
TranslateExistsCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.Between))
{
TranslateNotBetweenCondition(node);

return node;
}
else if (node.Method.Name == nameof(SQLQueryConditionExtension.NotBetween))
{
TranslateBetweenCondition(node);

return node;
}

throw new NotSupportedException(string.Format("The method '{0}' is not supported.", node.Method.Name));
}

private void TranslateBetweenCondition(MethodCallExpression methodCallExp)
{
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" BETWEEN ");
this.Visit(methodCallExp.Arguments[1]);
_queryBuilder.Append(" AND ");
this.Visit(methodCallExp.Arguments[2]);
}

private void TranslateNotBetweenCondition(MethodCallExpression methodCallExp)
{
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" NOT BETWEEN ");
this.Visit(methodCallExp.Arguments[1]);
_queryBuilder.Append(" AND ");
this.Visit(methodCallExp.Arguments[2]);
}

private void TranslateExistsCondition(MethodCallExpression methodCallExp)
{
_queryBuilder.Append("EXISTS ");
this.Visit(methodCallExp.Arguments[1]);
}

private void TranslateNotExistsCondition(MethodCallExpression methodCallExp)
{
_queryBuilder.Append("NOT EXISTS ");
this.Visit(methodCallExp.Arguments[1]);
}

private void TranslateInCondition(MethodCallExpression methodCallExp)
{
_queryBuilder.Append("(");
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" IN (");
this.Visit(methodCallExp.Arguments[1]);
_queryBuilder.Append("))");
}

private void TranslateNotInCondition(MethodCallExpression methodCallExp)
{
_queryBuilder.Append("(");
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" NOT IN (");
this.Visit(methodCallExp.Arguments[1]);
_queryBuilder.Append("))");
}

private void TranslateIsNullCondition(MethodCallExpression methodCallExp)
{
if (methodCallExp.Arguments.Count == 1)
{
_queryBuilder.Append("(");
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" IS NULL");
_queryBuilder.Append(")");
}
else
{
_queryBuilder.Append("ISNULL(");
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(", ");
this.Visit(methodCallExp.Arguments[1]);
_queryBuilder.Append(")");
}
}

private void TranslateIsNotNullCondition(MethodCallExpression methodCallExp)
{
_queryBuilder.Append("(");
this.Visit(methodCallExp.Arguments[0]);
_queryBuilder.Append(" IS NOT NULL");
_queryBuilder.Append(")");
}

private Expression VisitQueryOperationMethodCall(MethodCallExpression node)
{
if (node.Method.Name == nameof(SQLQueryOperationExtensions.Sum))
Expand Down Expand Up @@ -1627,6 +1779,21 @@ protected override Expression VisitUnary(UnaryExpression node)

return node;
}
else if (_fragmentType == SQLQueryFragmentType.Where &&
node.NodeType == ExpressionType.Not &&
node.Operand.NodeType == ExpressionType.Call)
{
var methodCallExp = (MethodCallExpression)node.Operand;
var declaringType = methodCallExp.Method.DeclaringType;
if (declaringType == typeof(SQLQueryConditionExtension))
{
return VisitQueryConditionNegationMethodCall(methodCallExp);
}
else if (declaringType == typeof(string))
{
return VisitStringNegationMethodCall(methodCallExp);
}
}

return base.VisitUnary(node);
}
Expand Down
10 changes: 10 additions & 0 deletions Lib/CSQLQueryExpress/Extensions/SQLQueryDefinitionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ public static SqlDbType Size(this SqlDbType type, int size)
return default;
}

public static SqlDbType Precision(this SqlDbType type, int precision)
{
return default;
}

public static SqlDbType Precision(this SqlDbType type, int precision, int scale)
{
return default;
}

public static SqlDbType Max(this SqlDbType type)
{
return default;
Expand Down
Loading

0 comments on commit 8c09b07

Please sign in to comment.