Skip to content

Commit d610c7d

Browse files
committed
Added support for VirtualDictionary
1 parent 9903320 commit d610c7d

4 files changed

Lines changed: 190 additions & 1 deletion

File tree

CoreHelpers.WindowsAzure.Storage.Table.Tests/ITS22PartialUpates.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public ITS22PartialUpates(IStorageContext context)
1616
}
1717

1818
[Fact]
19-
public async Task CreateAndVerifyBackup()
19+
public async Task VerifyPartialUpdate()
2020
{
2121
using (var scp = _rootContext.CreateChildContext())
2222
{
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using System;
2+
using CoreHelpers.WindowsAzure.Storage.Table.Backup;
3+
using CoreHelpers.WindowsAzure.Storage.Table.Tests.Contracts;
4+
using CoreHelpers.WindowsAzure.Storage.Table.Tests.Extensions;
5+
using CoreHelpers.WindowsAzure.Storage.Table.Tests.Models;
6+
7+
namespace CoreHelpers.WindowsAzure.Storage.Table.Tests
8+
{
9+
public class ITS23PartialDirectoryUpates
10+
{
11+
private readonly IStorageContext _rootContext;
12+
13+
public ITS23PartialDirectoryUpates(IStorageContext context)
14+
{
15+
_rootContext = context;
16+
}
17+
18+
[Fact]
19+
public async Task VerifyDirectoryUpdate()
20+
{
21+
using (var scp = _rootContext.CreateChildContext())
22+
{
23+
// set the tablename context
24+
scp.SetTableContext();
25+
26+
// configure the entity mapper
27+
scp.AddAttributeMapper<PartialDirectoryUpdateModel>();
28+
29+
// verify we don't have any value
30+
Assert.Empty(await scp.EnableAutoCreateTable().Query<PartialDirectoryUpdateModel>().InAllPartitions().Now());
31+
32+
33+
// insert the model with no dictionary
34+
await scp.MergeOrInsertAsync<PartialDirectoryUpdateModel>(new PartialDirectoryUpdateModel() { CustomerId = "C01", MeterId = "M01" });
35+
36+
var result = (await scp.EnableAutoCreateTable().Query<PartialDirectoryUpdateModel>().Now()).First();
37+
Assert.Empty(result.Costs.Values);
38+
39+
// insert the model with a 2 value dictionary
40+
await scp.MergeOrInsertAsync<PartialDirectoryUpdateModel>(new PartialDirectoryUpdateModel() { CustomerId = "C01", MeterId = "M01", Costs = new Dictionary<int, double>() {
41+
{ 1, 11.1 },
42+
{ 5, 55.5 }
43+
} });
44+
45+
result = (await scp.EnableAutoCreateTable().Query<PartialDirectoryUpdateModel>().Now()).First();
46+
Assert.Equal(2, result.Costs.Values.Count);
47+
Assert.Equal(11.1, result.Costs[1]);
48+
Assert.Equal(55.5, result.Costs[5]);
49+
Assert.False(result.Costs.ContainsKey(0));
50+
Assert.False(result.Costs.ContainsKey(2));
51+
Assert.False(result.Costs.ContainsKey(3));
52+
Assert.False(result.Costs.ContainsKey(4));
53+
54+
// add another value
55+
await scp.MergeOrInsertAsync<PartialDirectoryUpdateModel>(new PartialDirectoryUpdateModel()
56+
{
57+
CustomerId = "C01",
58+
MeterId = "M01",
59+
Costs = new Dictionary<int, double>() {
60+
{ 2, 22.2 }
61+
}
62+
});
63+
64+
result = (await scp.EnableAutoCreateTable().Query<PartialDirectoryUpdateModel>().Now()).First();
65+
Assert.Equal(3, result.Costs.Values.Count);
66+
Assert.Equal(11.1, result.Costs[1]);
67+
Assert.Equal(22.2, result.Costs[2]);
68+
Assert.Equal(55.5, result.Costs[5]);
69+
Assert.False(result.Costs.ContainsKey(0));
70+
Assert.False(result.Costs.ContainsKey(3));
71+
Assert.False(result.Costs.ContainsKey(4));
72+
73+
// override
74+
await scp.InsertOrReplaceAsync<PartialDirectoryUpdateModel>(new PartialDirectoryUpdateModel() { CustomerId = "C01", MeterId = "M01" });
75+
result = (await scp.EnableAutoCreateTable().Query<PartialDirectoryUpdateModel>().Now()).First();
76+
Assert.Empty(result.Costs.Values);
77+
78+
// clean up
79+
scp.DropTable<PartialDirectoryUpdateModel>();
80+
}
81+
}
82+
}
83+
}
84+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System;
2+
using CoreHelpers.WindowsAzure.Storage.Table.Attributes;
3+
4+
namespace CoreHelpers.WindowsAzure.Storage.Table.Tests.Models
5+
{
6+
[Storable(Tablename = "PartialDirectoryUpdate")]
7+
public class PartialDirectoryUpdateModel
8+
{
9+
10+
[PartitionKey]
11+
public string CustomerId { get; set; } = String.Empty;
12+
13+
[RowKey]
14+
public string MeterId { get; set; } = String.Empty;
15+
16+
[VirtualDictionary("DC")]
17+
public Dictionary<int, double> Costs { get; set; } = new Dictionary<int, double>();
18+
}
19+
}
20+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
using System;
2+
using System.Collections;
3+
using System.Linq;
4+
using System.Reflection;
5+
using System.Xml.Linq;
6+
using Azure.Data.Tables;
7+
using CoreHelpers.WindowsAzure.Storage.Table.Extensions;
8+
using CoreHelpers.WindowsAzure.Storage.Table.Serialization;
9+
using HandlebarsDotNet;
10+
11+
namespace CoreHelpers.WindowsAzure.Storage.Table.Attributes
12+
{
13+
public class VirtualDictionaryAttribute : Attribute, IVirtualTypeAttribute
14+
{
15+
private string _propertyPrefix;
16+
17+
public VirtualDictionaryAttribute(string PropertyPrefix)
18+
{
19+
_propertyPrefix = PropertyPrefix;
20+
}
21+
22+
public void ReadProperty<T>(TableEntity dataObject, PropertyInfo propertyInfo, T obj)
23+
{
24+
// search all properties with the prefix
25+
var keys = dataObject.Keys.Where(k => k.StartsWith(_propertyPrefix));
26+
27+
// visit every key
28+
foreach(var key in keys)
29+
{
30+
// check if we have the name
31+
if (!dataObject.ContainsKey(key))
32+
continue;
33+
34+
// prepare the key value
35+
var keyStringValue = key.Remove(0, _propertyPrefix.Length);
36+
37+
// read the value
38+
var dataObjectPropertyValue = dataObject[key];
39+
40+
// get the dictionary
41+
var dictionary = propertyInfo.GetValue(obj) as IDictionary;
42+
43+
// work with the type
44+
var arguments = dictionary.GetType().GetGenericArguments();
45+
var keyType = arguments[0];
46+
var valueType = arguments[1];
47+
48+
var keyValue = default(object);
49+
50+
switch(keyType.ToString())
51+
{
52+
case "System.Int32":
53+
keyValue = Convert.ToInt32(keyStringValue);
54+
break;
55+
default:
56+
keyValue = keyStringValue;
57+
break;
58+
}
59+
60+
dictionary.Add(keyValue, dataObjectPropertyValue);
61+
}
62+
}
63+
64+
public void WriteProperty<T>(PropertyInfo propertyInfo, T obj, TableEntityBuilder builder)
65+
{
66+
// get the value
67+
var dictionaryValue = propertyInfo.GetValue(obj);
68+
69+
// check if enumerable
70+
if ((dictionaryValue as IDictionary) == null)
71+
return;
72+
73+
// visit every element
74+
foreach(DictionaryEntry kvp in (dictionaryValue as IDictionary))
75+
{
76+
// generate the property name
77+
var propertyName = $"{_propertyPrefix}{kvp.Key}";
78+
79+
// write the property
80+
builder.AddProperty(propertyName, kvp.Value);
81+
}
82+
}
83+
}
84+
}
85+

0 commit comments

Comments
 (0)