Skip to content

Commit ccc2f7f

Browse files
toddbaertaskpt
andauthoredJul 29, 2024
feat: back targetingKey with internal map (#287)
Use the internal dictionary for the `targetingKey`. This is non-breaking from a compiler perspective. It could result in some behavioral changes, but IMO they are largely desirable. Fixes: #235 --------- Signed-off-by: Todd Baert <[email protected]> Co-authored-by: André Silva <[email protected]>
1 parent 2f8bd21 commit ccc2f7f

File tree

3 files changed

+70
-28
lines changed

3 files changed

+70
-28
lines changed
 

‎src/OpenFeature/Model/EvaluationContext.cs

+17-6
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,30 @@ namespace OpenFeature.Model
1111
/// <seealso href="https://github.com/open-feature/spec/blob/v0.5.2/specification/sections/03-evaluation-context.md">Evaluation context</seealso>
1212
public sealed class EvaluationContext
1313
{
14+
/// <summary>
15+
/// The index for the "targeting key" property when the EvaluationContext is serialized or expressed as a dictionary.
16+
/// </summary>
17+
internal const string TargetingKeyIndex = "targetingKey";
18+
19+
1420
private readonly Structure _structure;
1521

1622
/// <summary>
1723
/// Internal constructor used by the builder.
1824
/// </summary>
19-
/// <param name="targetingKey">The targeting key</param>
20-
/// <param name="content">The content of the context.</param>
21-
internal EvaluationContext(string? targetingKey, Structure content)
25+
/// <param name="content"></param>
26+
internal EvaluationContext(Structure content)
2227
{
23-
this.TargetingKey = targetingKey;
2428
this._structure = content;
2529
}
2630

31+
2732
/// <summary>
2833
/// Private constructor for making an empty <see cref="EvaluationContext"/>.
2934
/// </summary>
3035
private EvaluationContext()
3136
{
3237
this._structure = Structure.Empty;
33-
this.TargetingKey = string.Empty;
3438
}
3539

3640
/// <summary>
@@ -89,7 +93,14 @@ public IImmutableDictionary<string, Value> AsDictionary()
8993
/// <summary>
9094
/// Returns the targeting key for the context.
9195
/// </summary>
92-
public string? TargetingKey { get; }
96+
public string? TargetingKey
97+
{
98+
get
99+
{
100+
this._structure.TryGetValue(TargetingKeyIndex, out Value? targetingKey);
101+
return targetingKey?.AsString;
102+
}
103+
}
93104

94105
/// <summary>
95106
/// Return an enumerator for all values

‎src/OpenFeature/Model/EvaluationContextBuilder.cs

+2-21
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,6 @@ public sealed class EvaluationContextBuilder
1414
{
1515
private readonly StructureBuilder _attributes = Structure.Builder();
1616

17-
internal string? TargetingKey { get; private set; }
18-
1917
/// <summary>
2018
/// Internal to only allow direct creation by <see cref="EvaluationContext.Builder()"/>.
2119
/// </summary>
@@ -28,7 +26,7 @@ internal EvaluationContextBuilder() { }
2826
/// <returns>This builder</returns>
2927
public EvaluationContextBuilder SetTargetingKey(string targetingKey)
3028
{
31-
this.TargetingKey = targetingKey;
29+
this._attributes.Set(EvaluationContext.TargetingKeyIndex, targetingKey);
3230
return this;
3331
}
3432

@@ -138,23 +136,6 @@ public EvaluationContextBuilder Set(string key, DateTime value)
138136
/// <returns>This builder</returns>
139137
public EvaluationContextBuilder Merge(EvaluationContext context)
140138
{
141-
string? newTargetingKey = "";
142-
143-
if (!string.IsNullOrWhiteSpace(this.TargetingKey))
144-
{
145-
newTargetingKey = this.TargetingKey;
146-
}
147-
148-
if (!string.IsNullOrWhiteSpace(context.TargetingKey))
149-
{
150-
newTargetingKey = context.TargetingKey;
151-
}
152-
153-
if (!string.IsNullOrWhiteSpace(newTargetingKey))
154-
{
155-
this.TargetingKey = newTargetingKey;
156-
}
157-
158139
foreach (var kvp in context)
159140
{
160141
this.Set(kvp.Key, kvp.Value);
@@ -169,7 +150,7 @@ public EvaluationContextBuilder Merge(EvaluationContext context)
169150
/// <returns>An immutable <see cref="EvaluationContext"/></returns>
170151
public EvaluationContext Build()
171152
{
172-
return new EvaluationContext(this.TargetingKey, this._attributes.Build());
153+
return new EvaluationContext(this._attributes.Build());
173154
}
174155
}
175156
}

‎test/OpenFeature.Tests/OpenFeatureEvaluationContextTests.cs

+51-1
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public void TryGetValue_WhenCalledWithExistingKey_ReturnsTrueAndExpectedValue()
160160
var key = "testKey";
161161
var expectedValue = new Value("testValue");
162162
var structure = new Structure(new Dictionary<string, Value> { { key, expectedValue } });
163-
var evaluationContext = new EvaluationContext("targetingKey", structure);
163+
var evaluationContext = new EvaluationContext(structure);
164164

165165
// Act
166166
var result = evaluationContext.TryGetValue(key, out var actualValue);
@@ -169,5 +169,55 @@ public void TryGetValue_WhenCalledWithExistingKey_ReturnsTrueAndExpectedValue()
169169
Assert.True(result);
170170
Assert.Equal(expectedValue, actualValue);
171171
}
172+
173+
[Fact]
174+
public void GetValueOnTargetingKeySetWithTargetingKey_Equals_TargetingKey()
175+
{
176+
// Arrange
177+
var value = "my_targeting_key";
178+
var evaluationContext = EvaluationContext.Builder().SetTargetingKey(value).Build();
179+
180+
// Act
181+
var result = evaluationContext.TryGetValue(EvaluationContext.TargetingKeyIndex, out var actualFromStructure);
182+
var actualFromTargetingKey = evaluationContext.TargetingKey;
183+
184+
// Assert
185+
Assert.True(result);
186+
Assert.Equal(value, actualFromStructure?.AsString);
187+
Assert.Equal(value, actualFromTargetingKey);
188+
}
189+
190+
[Fact]
191+
public void GetValueOnTargetingKeySetWithStructure_Equals_TargetingKey()
192+
{
193+
// Arrange
194+
var value = "my_targeting_key";
195+
var evaluationContext = EvaluationContext.Builder().Set(EvaluationContext.TargetingKeyIndex, new Value(value)).Build();
196+
197+
// Act
198+
var result = evaluationContext.TryGetValue(EvaluationContext.TargetingKeyIndex, out var actualFromStructure);
199+
var actualFromTargetingKey = evaluationContext.TargetingKey;
200+
201+
// Assert
202+
Assert.True(result);
203+
Assert.Equal(value, actualFromStructure?.AsString);
204+
Assert.Equal(value, actualFromTargetingKey);
205+
}
206+
207+
[Fact]
208+
public void GetValueOnTargetingKeySetWithNonStringValue_Equals_Null()
209+
{
210+
// Arrange
211+
var evaluationContext = EvaluationContext.Builder().Set(EvaluationContext.TargetingKeyIndex, new Value(1)).Build();
212+
213+
// Act
214+
var result = evaluationContext.TryGetValue(EvaluationContext.TargetingKeyIndex, out var actualFromStructure);
215+
var actualFromTargetingKey = evaluationContext.TargetingKey;
216+
217+
// Assert
218+
Assert.True(result);
219+
Assert.Null(actualFromStructure?.AsString);
220+
Assert.Null(actualFromTargetingKey);
221+
}
172222
}
173223
}

0 commit comments

Comments
 (0)