Skip to content

Commit

Permalink
Merge pull request #29 from thygesteffensen/issue/3/collections
Browse files Browse the repository at this point in the history
Issue/3/collections
  • Loading branch information
thygesteffensen authored Jan 7, 2021
2 parents a773ff2 + bdf4b00 commit 708b2d6
Show file tree
Hide file tree
Showing 11 changed files with 489 additions and 31 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Parser.ExpressionParser.Functions.Base;

namespace Parser.ExpressionParser.Functions.Implementations.CollectionFunctions
{
public class ContainsFunction : Function
{
public ContainsFunction() : base("contains")
{
}

public override ValueContainer ExecuteFunction(params ValueContainer[] parameters)
{
var collection = parameters[0];
var value = parameters[1];

switch (collection.Type())
{
case ValueContainer.ValueType.Array:
var array = collection.GetValue<IEnumerable<ValueContainer>>();

switch (value.Type())
{
case ValueContainer.ValueType.Integer:
case ValueContainer.ValueType.Float:
case ValueContainer.ValueType.String:
case ValueContainer.ValueType.Boolean:
case ValueContainer.ValueType.Null:
return new ValueContainer(array.Contains(value));
case ValueContainer.ValueType.Array:
case ValueContainer.ValueType.Object:
return new ValueContainer(false);
default:
throw new ArgumentOutOfRangeException();
}
case ValueContainer.ValueType.Object:
var key = value.GetValue<string>();
return new ValueContainer(collection.AsDict().ContainsKey(key));
case ValueContainer.ValueType.String:
var text = collection.GetValue<string>();
var substring = value.GetValue<string>();
return new ValueContainer(text.Contains(substring));
default:
throw new PowerAutomateMockUpException($"Cannot perform contains on {collection.Type()}.");
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System.Collections.Generic;
using System.Linq;
using Parser.ExpressionParser.Functions.Base;

namespace Parser.ExpressionParser.Functions.Implementations.CollectionFunctions
{
public class EmptyFunction : Function
{
public EmptyFunction() : base("empty")
{
}

public override ValueContainer ExecuteFunction(params ValueContainer[] parameters)
{
var value = parameters[0];

return value.Type() switch
{
ValueContainer.ValueType.String => new ValueContainer(string.IsNullOrEmpty(value.GetValue<string>())),
ValueContainer.ValueType.Array => new ValueContainer(
!value.GetValue<IEnumerable<ValueContainer>>().Any()),
ValueContainer.ValueType.Object => new ValueContainer(
value.GetValue<Dictionary<string, ValueContainer>>().Count == 0),
ValueContainer.ValueType.Null => new ValueContainer(true),
_ => throw new PowerAutomateMockUpException(
$"Empty expression can only operate on String, Array or Object types, not {value.Type()}.")
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using System.Linq;
using Parser.ExpressionParser.Functions.Base;

namespace Parser.ExpressionParser.Functions.Implementations.CollectionFunctions
{
public class FirstFunction : Function
{
public FirstFunction() : base("first")
{
}

public override ValueContainer ExecuteFunction(params ValueContainer[] parameters)
{
var value = parameters[0];

return value.Type() switch
{
ValueContainer.ValueType.String => new ValueContainer(
value.GetValue<string>().Substring(0, 1)),
ValueContainer.ValueType.Array => new ValueContainer(
value.GetValue<IEnumerable<ValueContainer>>().First()),
_ => throw new PowerAutomateMockUpException(
$"Empty expression can only operate on String or Array types, not {value.Type()}.")
};
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
using System.Collections.Generic;
using System.Linq;
using Parser.ExpressionParser.Functions.Base;

namespace Parser.ExpressionParser.Functions.Implementations.CollectionFunctions
{
public class InterSectionFunction : Function
{
public InterSectionFunction() : base("intersection")
{
}

public override ValueContainer ExecuteFunction(params ValueContainer[] parameters)
{
return parameters[0].Type() switch
{
ValueContainer.ValueType.Array => IntersectList(parameters),
ValueContainer.ValueType.Object => IntersectDict(parameters),
_ => throw new PowerAutomateMockUpException(
$"Can only intersect Array and Object, not {parameters[0].Type()}.")
};
}

private ValueContainer IntersectDict(IReadOnlyList<ValueContainer> parameters)
{
var first = parameters[0].GetValue<Dictionary<string, ValueContainer>>();

var intersect =
ToDictionary(first, parameters[1]);

if (parameters.Count > 2)
{
intersect = parameters.Skip(2).Aggregate(intersect, ToDictionary);
}

return new ValueContainer(intersect);
}

private Dictionary<string, ValueContainer> ToDictionary(Dictionary<string, ValueContainer> first,
ValueContainer valueContainer)
{
var second = valueContainer.GetValue<Dictionary<string, ValueContainer>>();

return first.Where(x => second.ContainsKey(x.Key))
.ToDictionary(x => x.Key, x => second[x.Key]);
}

private ValueContainer IntersectList(IReadOnlyList<ValueContainer> parameters)
{
var first = parameters[0].GetValue<IEnumerable<ValueContainer>>();
var second = parameters[1].GetValue<IEnumerable<ValueContainer>>();

var intersection = first.Intersect(second, new ValueContainerComparer());

if (parameters.Count > 2)
{
intersection = parameters.Skip(2)
.Select(valueContainer => valueContainer.GetValue<IEnumerable<ValueContainer>>())
.Aggregate(intersection, (current, collection) => current.Intersect(collection));
}

return new ValueContainer(intersection);
}
}
}
53 changes: 45 additions & 8 deletions PowerAutomateMockUp/ExpressionParser/ValueContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ public override string ToString()
ValueType.String => _value,
ValueType.Object => "{" + string.Join(",", GetValue<Dictionary<string, ValueContainer>>()
.Select(kv => kv.Key + "=" + kv.Value).ToArray()) + "}",
ValueType.Array => "[" + string.Join(", ", GetValue<ValueContainer[]>().ToList()) + "]",
ValueType.Array => "[" + string.Join(", ", GetValue<IEnumerable<ValueContainer>>().ToList()) + "]",
ValueType.Null => "<null>",
_ => throw new ArgumentOutOfRangeException()
};
Expand All @@ -314,7 +314,8 @@ public bool IsNull()

public int CompareTo(object? obj)
{
if (obj == null || obj.GetType() != GetType()) throw new InvalidOperationException("Cannot compare these two...");
if (obj == null || obj.GetType() != GetType())
throw new InvalidOperationException("Cannot compare these two...");

var other = (ValueContainer) obj;
if (other.Type() != _type)
Expand Down Expand Up @@ -351,21 +352,57 @@ public bool Equals(ValueContainer other)
{
if (ReferenceEquals(null, other)) return false;
if (ReferenceEquals(this, other)) return true;
return Equals(_value, other._value) && _type == other._type;

switch (_type)
{
case ValueType.Array when other._type == ValueType.Array:
{
var thisArray = (IEnumerable<ValueContainer>) _value;
var otherArray = other.GetValue<IEnumerable<ValueContainer>>();

return thisArray.SequenceEqual(otherArray);
}
case ValueType.Object when other._type == ValueType.Object:
{
var thisDict = (Dictionary<string, ValueContainer>) _value;
var otherDict = other.GetValue<Dictionary<string, ValueContainer>>();

return thisDict.Count == otherDict.Count && !thisDict.Except(otherDict).Any();
}
default:
return Equals(_value, other._value) && _type == other._type;
}
}

public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((ValueContainer) obj);
return obj.GetType() == GetType() && Equals((ValueContainer) obj);
}

/*public override int GetHashCode()
public override int GetHashCode()
{
return HashCode.Combine(_value, (int) _type);
}*/
return new {_type, _value}.GetHashCode();
}
}

public class ValueContainerComparer : EqualityComparer<ValueContainer>
{
public override bool Equals(ValueContainer x, ValueContainer y)
{
if (x == null || y == null)
{
return x == null && y == null;
}

return x.Equals(y);
}

public override int GetHashCode(ValueContainer obj)
{
return obj.GetHashCode();
}
}

static class ValueContainerExtensions
Expand Down
1 change: 0 additions & 1 deletion PowerAutomateMockUp/PowerAutomateMockUp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
</ItemGroup>

<ItemGroup>
<Folder Include="ExpressionParser\Functions\Implementations\CollectionFunctions" />
<Folder Include="ExpressionParser\Functions\Implementations\ConversionFunctions" />
<Folder Include="ExpressionParser\Functions\Implementations\LogicalComparisonFunctions" />
</ItemGroup>
Expand Down
20 changes: 11 additions & 9 deletions Test/ActionTests/SwitchActionTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ public async Task SwitchTestWithNoActions()
var expressionEngine = new Mock<IExpressionEngine>();

expressionEngine.Setup(x => x.Parse(It.IsAny<string>())).Returns("CaseWithoutActions");

var switchActionExecutor = new SwitchActionExecutor(sdm.Object, logger, expressionEngine.Object);
switchActionExecutor.InitializeActionExecutor("ActionName", JToken.Parse(SwitchAction));

Expand All @@ -72,12 +72,14 @@ public async Task SwitchTestWithNoActions()
Assert.AreEqual(ActionStatus.Succeeded, result.ActionStatus);

sdm.Verify(
x => x.Push(It.IsAny<string>(), It.IsAny<IEnumerable<JProperty>>(), It.IsAny<IScopeActionExecutor>()),
x => x.Push(It.IsAny<string>(),
It.IsAny<IEnumerable<JProperty>>()
, It.IsAny<IScopeActionExecutor>()),
Times.Never);
expressionEngine.Verify(x=> x.Parse(It.IsAny<string>()), Times.Once);

expressionEngine.Verify(x => x.Parse(It.IsAny<string>()), Times.Once);
}

[Test]
public async Task SwitchTestWithActions()
{
Expand All @@ -88,20 +90,20 @@ public async Task SwitchTestWithActions()
var expressionEngine = new Mock<IExpressionEngine>();

expressionEngine.Setup(x => x.Parse(It.IsAny<string>())).Returns("CaseWithActions");

var switchActionExecutor = new SwitchActionExecutor(sdm.Object, logger, expressionEngine.Object);
switchActionExecutor.InitializeActionExecutor("ActionName", JToken.Parse(SwitchAction));

var result = await switchActionExecutor.Execute();

Assert.AreEqual("Update_a_record",result.NextAction);
Assert.AreEqual("Update_a_record", result.NextAction);
Assert.AreEqual(ActionStatus.Succeeded, result.ActionStatus);

sdm.Verify(
x => x.Push(It.IsAny<string>(), It.IsAny<IEnumerable<JProperty>>(), It.IsAny<IScopeActionExecutor>()),
Times.Once);
expressionEngine.Verify(x=> x.Parse(It.IsAny<string>()), Times.Once);

expressionEngine.Verify(x => x.Parse(It.IsAny<string>()), Times.Once);
}
}
}
Loading

0 comments on commit 708b2d6

Please sign in to comment.