Skip to content

Commit d0ff307

Browse files
authored
Merge pull request #13 from altasoft/bugfix/dicitionaryKey
improve dictionary support
2 parents d2f155e + 2cc6e69 commit d0ff307

4 files changed

Lines changed: 83 additions & 1 deletion

File tree

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<Product>Simpra</Product>
1010
<Company>ALTA Software llc.</Company>
1111
<Copyright>Copyright © 2024 ALTA Software llc.</Copyright>
12-
<Version>1.0.12</Version>
12+
<Version>1.0.13</Version>
1313
</PropertyGroup>
1414

1515
<PropertyGroup>

src/AltaSoft.Simpra/Visitor/SimpraParserVisitor.cs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,14 @@ public Expression VisitIndexAccess(SimpraParser.IndexAccessContext context)
263263
objectType = left.Type;
264264
}
265265

266+
// Handle IDictionary<TKey, TValue> (including Dictionary<,>)
267+
var isDictionary = objectType.IsIReadOnlyDictionaryT();
268+
269+
if (isDictionary)
270+
{
271+
return HandleDictionaryIndexAccess(context, objectType, index, left);
272+
}
273+
266274
// Handle indexable types (e.g., List<T>)
267275
var defaultIndexer = objectType
268276
.GetProperties()
@@ -552,4 +560,21 @@ public Expression VisitArray(SimpraParser.ArrayContext context)
552560
{
553561
return NewSimpraList(context.exp().Select(Visit), context);
554562
}
563+
564+
private static Expression HandleDictionaryIndexAccess(SimpraParser.IndexAccessContext context, Type objectType, Expression index, Expression left)
565+
{
566+
var keyType = objectType.GetGenericArguments()[0];
567+
var valueType = objectType.GetGenericArguments()[1];
568+
var tryGetValueMethod = objectType.GetMethod("TryGetValue", [keyType, valueType.MakeByRefType()])!;
569+
570+
var keyExpr = index.Type != keyType ? Expression.Convert(index, keyType) : index;
571+
var valueVar = Expression.Variable(valueType, "dictValue");
572+
573+
var tryGetValueCall = Expression.Call(left, tryGetValueMethod, keyExpr, valueVar);
574+
575+
var defaultValue = Expression.Default(valueType);
576+
var block = Expression.Block([valueVar], Expression.Condition(tryGetValueCall, valueVar, defaultValue));
577+
578+
return ConvertToSimpraType(block, false, context);
579+
}
555580
}

tests/AltaSoft.Simpra.tests/Models/TestModel.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ public class TestModel : BaseModel, ITransferModel
3030
public required Transfer? Transfer { get; set; }
3131
public required Customer Customer { get; set; }
3232
public required string Remittance { get; set; }
33+
public Dictionary<string, string>? Countries { get; set; }
34+
35+
public Dictionary<string, Customer>? DictionaryOfObjects { get; set; }
3336

3437
public ColorX ColorX { get; set; } = ColorX.Green;
3538
public ColorM ColorM { get; set; } = ColorM.Green;

tests/AltaSoft.Simpra.tests/SimpraExpressionTests.cs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,60 @@ namespace AltaSoft.Simpra.Tests;
44

55
public class SimpraExpressionTests
66
{
7+
8+
[Fact]
9+
public void DictionaryIndexer_MissingKey_ReturnsDefaultValueForProperty()
10+
{
11+
const string expressionCode =
12+
"""
13+
return DictionaryOfObjects['test'].Id
14+
""";
15+
16+
var simpra = new Simpra();
17+
var model = GetTestModel();
18+
model.DictionaryOfObjects = new Dictionary<string, Customer> { { "Georgia", new Customer
19+
{
20+
Id = 1,
21+
Status = 10
22+
}} };
23+
24+
var result = simpra.Execute<int, TestModel, IFunctions>(model, new TestFunctions(), expressionCode);
25+
Assert.Equal(0, result);
26+
27+
}
28+
29+
[Fact]
30+
public void CallGetValueFromDictionaryWhenKeyDoesNotExist_ShouldReturnDefault()
31+
{
32+
const string expressionCode =
33+
"""
34+
return Countries['test'] is 'Test'
35+
""";
36+
37+
var simpra = new Simpra();
38+
var model = GetTestModel();
39+
model.Countries = new Dictionary<string, string> { { "Georgia", "Test" } };
40+
var result = simpra.Execute<bool, TestModel, IFunctions>(model, new TestFunctions(), expressionCode);
41+
Assert.False(result);
42+
43+
}
44+
45+
[Fact]
46+
public void CallGetValueFromDictionaryWhenKeyExist_ShouldReturnValue()
47+
{
48+
const string expressionCode =
49+
"""
50+
return Countries['Georgia'] is 'Test'
51+
""";
52+
53+
var simpra = new Simpra();
54+
var model = GetTestModel();
55+
model.Countries = new Dictionary<string, string> { { "Georgia", "Test" } };
56+
var result = simpra.Execute<bool, TestModel, IFunctions>(model, new TestFunctions(), expressionCode);
57+
Assert.True(result);
58+
59+
}
60+
761
[Fact]
862
public void CallInterfaceFunctionFromSimpra_ShouldReturnCorrectValue()
963
{

0 commit comments

Comments
 (0)