Skip to content

Commit

Permalink
Implement special IIF method to run only ifTrue|ifFalse according test
Browse files Browse the repository at this point in the history
  • Loading branch information
mbdavid committed Feb 9, 2020
1 parent 35e4935 commit 0628f8e
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 9 deletions.
23 changes: 21 additions & 2 deletions LiteDB.Tests/Expressions/Expressions_Tests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using FluentAssertions;
using System.Collections.Generic;
using Xunit;

namespace LiteDB.Tests.Expressions
Expand Down Expand Up @@ -228,7 +229,25 @@ public void Expression_AndAlso_OrElse()
// KO (expected: false, actual: exception)
doc1["x"] = "123";
var r2 = ex1.ExecuteScalar(doc1);

}

[Fact]
public void Expression_Conditional_IIF()
{
var ex1 = BsonExpression.Create("IIF(LENGTH($.x) >= 5, SUBSTRING($.x, 0, 5), \"too-short\")");
var doc1 = new BsonDocument();

// OK ("12345")
doc1["x"] = "123456789";
var r1 = ex1.ExecuteScalar(doc1);

r1.AsString.Should().Be("12345");

// KO (expected: "too-short", actual: System.ArgumentOutOfRangeException: Index and length must refer to a location within the string.)
doc1["x"] = "123";
var r2 = ex1.ExecuteScalar(doc1);

r2.AsString.Should().Be("too-short");
}
}
}
11 changes: 4 additions & 7 deletions LiteDB/Document/Expression/Methods/Misc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,14 +119,11 @@ public static BsonValue OID_CREATIONTIME(BsonValue objectId)
/// <summary>
/// Conditional IF statment. If condition are true, returns TRUE value, otherwise, FALSE value
/// </summary>
public static BsonValue IIF(BsonValue condition, BsonValue ifTrue, BsonValue ifFalse)
public static BsonValue IIF(BsonValue test, BsonValue ifTrue, BsonValue ifFalse)
{
if (condition.IsBoolean)
{
return condition.AsBoolean ? ifTrue : ifFalse;
}

return BsonValue.Null;
// this method are not implemented because will use "Expression.Conditional"
// will execute "ifTrue" only if test = true and will execute "ifFalse" if test = false
throw new NotImplementedException();
}

/// <summary>
Expand Down
28 changes: 28 additions & 0 deletions LiteDB/Document/Expression/Parser/BsonExpressionParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -931,6 +931,9 @@ private static BsonExpression TryParseMethodCall(Tokenizer tokenizer, Expression
}
}

// special IIF case
if (method.Name == "IIF" && pars.Count == 3) return CreateConditionalExpression(pars[0], pars[1], pars[2]);

return new BsonExpression
{
Type = BsonExpressionType.Call,
Expand Down Expand Up @@ -1433,5 +1436,30 @@ internal static BsonExpression CreateLogicExpression(BsonExpressionType type, Bs

return result;
}

/// <summary>
/// Create new conditional (IIF) expression. Execute expression only if True or False value
/// </summary>
internal static BsonExpression CreateConditionalExpression(BsonExpression test, BsonExpression ifTrue, BsonExpression ifFalse)
{
// convert BsonValue into Boolean
var boolTest = Expression.Property(test.Expression, typeof(BsonValue), "AsBoolean");

var expr = Expression.Condition(boolTest, ifTrue.Expression, ifFalse.Expression);

// create new binary expression based in 2 other expressions
var result = new BsonExpression
{
Type = BsonExpressionType.Call, // there is not specific Conditional
IsImmutable = test.IsImmutable && ifTrue.IsImmutable || ifFalse.IsImmutable,
UseSource = test.UseSource || ifTrue.UseSource || ifFalse.UseSource,
IsScalar = test.IsScalar && ifTrue.IsScalar && ifFalse.IsScalar,
Fields = new HashSet<string>(StringComparer.OrdinalIgnoreCase).AddRange(test.Fields).AddRange(ifTrue.Fields).AddRange(ifFalse.Fields),
Expression = expr,
Source = "IIF(" + test.Source + "," + ifTrue.Source + "," + ifFalse.Source + ")"
};

return result;
}
}
}

0 comments on commit 0628f8e

Please sign in to comment.