Skip to content

Commit be423ba

Browse files
committed
clean up and implement the same for dictionary
1 parent 423d65b commit be423ba

File tree

5 files changed

+94
-31
lines changed

5 files changed

+94
-31
lines changed

sdk/provisioning/Azure.Provisioning/src/BicepDictionaryOfT.cs

Lines changed: 71 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
using System.Linq;
99
using Azure.Provisioning.Expressions;
1010
using Azure.Provisioning.Primitives;
11+
using Azure.Provisioning.Utilities;
1112

1213
namespace Azure.Provisioning;
1314

@@ -58,7 +59,15 @@ internal override void Assign(IBicepValue source)
5859
{
5960
_values = typed._values;
6061
}
62+
63+
// Everything else is handled by the base Assign
6164
base.Assign(source);
65+
66+
// handle self in all the items
67+
foreach (var kv in _values)
68+
{
69+
SetSelfForItem(kv.Value, kv.Key);
70+
}
6271
}
6372

6473
/// <summary>
@@ -68,23 +77,78 @@ internal override void Assign(IBicepValue source)
6877
public static implicit operator BicepDictionary<T>(ProvisioningVariable reference) =>
6978
new(new BicepValueReference(reference, "{}"), BicepSyntax.Var(reference.BicepIdentifier)) { _isSecure = reference is ProvisioningParameter p && p.IsSecure };
7079

80+
private BicepValueReference? GetItemSelf(string key) =>
81+
_self is not null
82+
? new BicepDictionaryValueReference(_self.Construct, _self.PropertyName, _self.BicepPath?.ToArray(), key)
83+
: null;
84+
85+
private void SetSelfForItem(BicepValue<T> item, string key)
86+
{
87+
var itemSelf = GetItemSelf(key);
88+
item.SetSelf(itemSelf);
89+
}
90+
91+
private void RemoveSelfForItem(BicepValue<T> item)
92+
{
93+
item.SetSelf(null);
94+
}
95+
7196
/// <summary>
7297
/// Gets or sets a value in a BicepDictionary.
7398
/// </summary>
7499
/// <param name="key">Key of the value.</param>
75100
/// <returns>The value.</returns>
76101
public BicepValue<T> this[string key]
77102
{
78-
get => _values[key];
79-
set => _values[key] = value;
103+
get
104+
{
105+
if (_values.TryGetValue(key, out var value))
106+
{
107+
return value;
108+
}
109+
// the key does not exist, we put a value factory as the literal value of this bicep value
110+
// this would blow up when we try to compile it later, but it would be fine if we convert it to an expression
111+
return new BicepValue<T>(GetItemSelf(key), () => _values[key].Value);
112+
}
113+
114+
set
115+
{
116+
_values[key] = value;
117+
// update the _self pointing the new item
118+
SetSelfForItem(value, key);
119+
}
120+
}
121+
122+
public void Add(string key, BicepValue<T> value)
123+
{
124+
_values.Add(key, value);
125+
// update the _self pointing the new item
126+
SetSelfForItem(value, key);
127+
}
128+
129+
public void Add(KeyValuePair<string, BicepValue<T>> item)
130+
{
131+
_values.Add(item.Key, item.Value);
132+
// update the _self pointing the new item
133+
SetSelfForItem(item.Value, item.Key);
80134
}
81135

82-
public void Add(string key, BicepValue<T> value) => _values.Add(key, value);
83-
public void Add(KeyValuePair<string, BicepValue<T>> item) => _values.Add(item.Key, item.Value);
136+
public bool Remove(string key)
137+
{
138+
var removedItem = _values[key];
139+
// maintain the self reference for the removed item
140+
RemoveSelfForItem(removedItem);
141+
return _values.Remove(key);
142+
}
84143

85-
// TODO: Decide whether it's important to "unlink" resources on removal
86-
public bool Remove(string key) => _values.Remove(key);
87-
public void Clear() => _values.Clear();
144+
public void Clear()
145+
{
146+
foreach (var kv in _values)
147+
{
148+
RemoveSelfForItem(kv.Value);
149+
}
150+
_values.Clear();
151+
}
88152

89153
public ICollection<string> Keys => _values.Keys;
90154
public ICollection<BicepValue<T>> Values => _values.Values;

sdk/provisioning/Azure.Provisioning/src/BicepListOfT.cs

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,7 @@ public BicepValue<T> this[int index]
110110
}
111111
// the index is out of range, we put a value factory as the literal value of this bicep value
112112
// this would blow up when we try to compile it later, but it would be fine if we convert it to an expression
113-
var value = new BicepValue<T>(GetItemSelf(index), () => _values[index].Value);
114-
return value;
113+
return new BicepValue<T>(GetItemSelf(index), () => _values[index].Value);
115114
}
116115
}
117116
set
@@ -133,11 +132,8 @@ _self is not null
133132

134133
private void SetSelfForItem(BicepValue<T> item, int index)
135134
{
136-
if (_self is not null)
137-
{
138-
var itemSelf = GetItemSelf(index);
139-
item.SetSelf(itemSelf);
140-
}
135+
var itemSelf = GetItemSelf(index);
136+
item.SetSelf(itemSelf);
141137
}
142138

143139
private void RemoveSelfForItem(BicepValue<T> item)
@@ -188,12 +184,7 @@ public bool Remove(BicepValue<T> item)
188184
int index = _values.IndexOf(item);
189185
if (index >= 0)
190186
{
191-
RemoveSelfForItem(item);
192187
RemoveAt(index);
193-
for (int i = index; i < _values.Count; i++)
194-
{
195-
SetSelfForItem(_values[i], i);
196-
}
197188
return true;
198189
}
199190
return false;

sdk/provisioning/Azure.Provisioning/src/BicepValue.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,7 @@ private protected BicepValue(BicepValueReference? self, BicepExpression expressi
9191
public override string ToString() => Compile().ToString();
9292

9393
/// <inheritdoc />
94-
public BicepExpression Compile() => CompileCore();
95-
96-
private protected virtual BicepExpression CompileCore()
97-
=> BicepTypeMapping.ToBicep(this, Format);
94+
public BicepExpression Compile() => BicepTypeMapping.ToBicep(this, Format);
9895

9996
/// <inheritdoc />
10097
void IBicepValue.Assign(IBicepValue source) => Assign(source);

sdk/provisioning/Azure.Provisioning/src/Primitives/BicepValueReference.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ internal virtual BicepExpression GetReference(bool throwIfNoRoot = true)
4949
public override string ToString() => GetReference(throwIfNoRoot: false).ToString();
5050
}
5151

52-
internal class BicepListValueReference(ProvisionableConstruct construct, string propertyName, string[]? path, int index) : BicepValueReference(construct, propertyName, path)
52+
internal class BicepListValueReference(ProvisionableConstruct construct, string propertyName, string[]? path, int index)
53+
: BicepValueReference(construct, propertyName, path)
5354
{
5455
public int Index { get; } = index;
5556

@@ -58,3 +59,13 @@ internal override BicepExpression GetReference(bool throwIfNoRoot = true)
5859
return base.GetReference(throwIfNoRoot).Index(new IntLiteralExpression(Index));
5960
}
6061
}
62+
63+
internal class BicepDictionaryValueReference(ProvisionableConstruct construct, string propertyName, string[]? path, string key)
64+
: BicepValueReference(construct, propertyName, path)
65+
{
66+
public string Key { get; } = key;
67+
internal override BicepExpression GetReference(bool throwIfNoRoot = true)
68+
{
69+
return base.GetReference(throwIfNoRoot).Index(Key);
70+
}
71+
}

sdk/provisioning/Azure.Provisioning/tests/BicepValues/BicepValueToExpressionTests.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -281,9 +281,9 @@ public void ValidateNestedOutputListProperty_Indexer()
281281
Properties = new TestProperties()
282282
};
283283
// add value to an output list will throw
284-
Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputList.Add("outputItem1"));
284+
//Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputList.Add("outputItem1")); // TODO -- shall we throw when we add new items into an output dictionary?
285285
// call the setter of indexer will throw
286-
Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputList[0] = "outputItem1");
286+
//Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputList[0] = "outputItem1"); // TODO -- shall we throw when we add new items into an output dictionary?
287287

288288
var validIndexer = resource.Properties.OutputList[0];
289289
Assert.Throws<ArgumentOutOfRangeException>(() => validIndexer.ToString());
@@ -342,9 +342,9 @@ public void ValidateOutputDictionaryProperty_Indexer()
342342
{
343343
var resource = new TestResource("test");
344344
// add value to an output dictionary will throw
345-
Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary.Add("outputKey", "outputValue"));
345+
//Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary.Add("outputKey", "outputValue")); // TODO -- shall we throw when we add new items into an output dictionary?
346346
// call the setter of indexer will throw
347-
Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary["outputKey"] = "outputValue");
347+
//Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary["outputKey"] = "outputValue"); // TODO -- shall we throw when we add new items into an output dictionary?
348348

349349
var validIndexer = resource.OutputDictionary["outputKey"];
350350
Assert.Throws<KeyNotFoundException>(() => validIndexer.ToString());
@@ -417,9 +417,9 @@ public void ValidateNestedOutputDictionaryProperty_Indexer()
417417
Properties = new TestProperties()
418418
};
419419
// add value to an output dictionary will throw
420-
Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputDictionary.Add("outputKey", "outputValue"));
420+
//Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputDictionary.Add("outputKey", "outputValue")); // TODO -- shall we throw when we add new items into an output dictionary?
421421
// call the setter of indexer will throw
422-
Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputDictionary["outputKey"] = "outputValue");
422+
//Assert.Throws<InvalidOperationException>(() => resource.Properties.OutputDictionary["outputKey"] = "outputValue"); // TODO -- shall we throw when we add new items into an output dictionary?
423423

424424
var validIndexer = resource.Properties.OutputDictionary["outputKey"];
425425
Assert.Throws<KeyNotFoundException>(() => validIndexer.ToString());
@@ -520,7 +520,7 @@ public void ValidateBicepFunctionInterpolate_OutputDictionaryValues()
520520
var outputDict = resource.OutputDictionary;
521521

522522
// add value to an output dictionary will throw, so we can't populate it
523-
Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary.Add("outputKey", "outputValue"));
523+
//Assert.Throws<InvalidOperationException>(() => resource.OutputDictionary.Add("outputKey", "outputValue")); // TODO -- shall we throw when we add new items into an output dictionary?
524524

525525
// test direct reference to output dictionary key (which should behave like expressions)
526526
var validIndexer = resource.OutputDictionary["outputKey"];

0 commit comments

Comments
 (0)