Skip to content

Commit fd0a541

Browse files
authored
feat: Flag metadata (open-feature#223)
1 parent d792b32 commit fd0a541

File tree

6 files changed

+369
-4
lines changed

6 files changed

+369
-4
lines changed

src/OpenFeature/Model/BaseMetadata.cs

+76
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.Immutable;
4+
5+
#nullable enable
6+
namespace OpenFeature.Model;
7+
8+
/// <summary>
9+
/// Represents the base class for metadata objects.
10+
/// </summary>
11+
public abstract class BaseMetadata
12+
{
13+
private readonly ImmutableDictionary<string, object> _metadata;
14+
15+
internal BaseMetadata(Dictionary<string, object> metadata)
16+
{
17+
this._metadata = metadata.ToImmutableDictionary();
18+
}
19+
20+
/// <summary>
21+
/// Gets the boolean value associated with the specified key.
22+
/// </summary>
23+
/// <param name="key">The key of the value to retrieve.</param>
24+
/// <returns>The boolean value associated with the key, or null if the key is not found.</returns>
25+
public virtual bool? GetBool(string key)
26+
{
27+
return this.GetValue<bool>(key);
28+
}
29+
30+
/// <summary>
31+
/// Gets the integer value associated with the specified key.
32+
/// </summary>
33+
/// <param name="key">The key of the value to retrieve.</param>
34+
/// <returns>The integer value associated with the key, or null if the key is not found.</returns>
35+
public virtual int? GetInt(string key)
36+
{
37+
return this.GetValue<int>(key);
38+
}
39+
40+
/// <summary>
41+
/// Gets the double value associated with the specified key.
42+
/// </summary>
43+
/// <param name="key">The key of the value to retrieve.</param>
44+
/// <returns>The double value associated with the key, or null if the key is not found.</returns>
45+
public virtual double? GetDouble(string key)
46+
{
47+
return this.GetValue<double>(key);
48+
}
49+
50+
/// <summary>
51+
/// Gets the string value associated with the specified key.
52+
/// </summary>
53+
/// <param name="key">The key of the value to retrieve.</param>
54+
/// <returns>The string value associated with the key, or null if the key is not found.</returns>
55+
public virtual string? GetString(string key)
56+
{
57+
var hasValue = this._metadata.TryGetValue(key, out var value);
58+
if (!hasValue)
59+
{
60+
return null;
61+
}
62+
63+
return value as string ?? null;
64+
}
65+
66+
private T? GetValue<T>(string key) where T : struct
67+
{
68+
var hasValue = this._metadata.TryGetValue(key, out var value);
69+
if (!hasValue)
70+
{
71+
return null;
72+
}
73+
74+
return value is T tValue ? tValue : null;
75+
}
76+
}

src/OpenFeature/Model/FlagEvaluationDetails.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ namespace OpenFeature.Model
66
/// The contract returned to the caller that describes the result of the flag evaluation process.
77
/// </summary>
88
/// <typeparam name="T">Flag value type</typeparam>
9-
/// <seealso href="https://github.com/open-feature/spec/blob/v0.5.2/specification/types.md#evaluation-details"/>
9+
/// <seealso href="https://github.com/open-feature/spec/blob/v0.7.0/specification/types.md#evaluation-details"/>
1010
public sealed class FlagEvaluationDetails<T>
1111
{
1212
/// <summary>
@@ -45,6 +45,11 @@ public sealed class FlagEvaluationDetails<T>
4545
/// </summary>
4646
public string Variant { get; }
4747

48+
/// <summary>
49+
/// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number.
50+
/// </summary>
51+
public FlagMetadata FlagMetadata { get; }
52+
4853
/// <summary>
4954
/// Initializes a new instance of the <see cref="FlagEvaluationDetails{T}"/> class.
5055
/// </summary>
@@ -54,15 +59,17 @@ public sealed class FlagEvaluationDetails<T>
5459
/// <param name="reason">Reason</param>
5560
/// <param name="variant">Variant</param>
5661
/// <param name="errorMessage">Error message</param>
62+
/// <param name="flagMetadata">Flag metadata</param>
5763
public FlagEvaluationDetails(string flagKey, T value, ErrorType errorType, string reason, string variant,
58-
string errorMessage = null)
64+
string errorMessage = null, FlagMetadata flagMetadata = null)
5965
{
6066
this.Value = value;
6167
this.FlagKey = flagKey;
6268
this.ErrorType = errorType;
6369
this.Reason = reason;
6470
this.Variant = variant;
6571
this.ErrorMessage = errorMessage;
72+
this.FlagMetadata = flagMetadata;
6673
}
6774
}
6875
}

src/OpenFeature/Model/FlagMetadata.cs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.Immutable;
4+
5+
#nullable enable
6+
namespace OpenFeature.Model;
7+
8+
/// <summary>
9+
/// Represents the metadata associated with a feature flag.
10+
/// </summary>
11+
/// <seealso href="https://github.com/open-feature/spec/blob/v0.7.0/specification/types.md#flag-metadata"/>
12+
public sealed class FlagMetadata : BaseMetadata
13+
{
14+
/// <summary>
15+
/// Constructor for the <see cref="BaseMetadata"/> class.
16+
/// </summary>
17+
public FlagMetadata() : this([])
18+
{
19+
}
20+
21+
/// <summary>
22+
/// Constructor for the <see cref="BaseMetadata"/> class.
23+
/// </summary>
24+
/// <param name="metadata">The dictionary containing the metadata.</param>
25+
public FlagMetadata(Dictionary<string, object> metadata) : base(metadata)
26+
{
27+
}
28+
}

src/OpenFeature/Model/ProviderEvents.cs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class ProviderEventPayload
3636
/// <summary>
3737
/// Metadata information for the event.
3838
/// </summary>
39+
// TODO: This needs to be changed to a EventMetadata object
3940
public Dictionary<string, object> EventMetadata { get; set; }
4041
}
4142
}

src/OpenFeature/Model/ResolutionDetails.cs

+9-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace OpenFeature.Model
77
/// Describes the details of the feature flag being evaluated
88
/// </summary>
99
/// <typeparam name="T">Flag value type</typeparam>
10-
/// <seealso href="https://github.com/open-feature/spec/blob/v0.5.2/specification/types.md#resolution-details"/>
10+
/// <seealso href="https://github.com/open-feature/spec/blob/v0.7.0/specification/types.md#resolution-details"/>
1111
public sealed class ResolutionDetails<T>
1212
{
1313
/// <summary>
@@ -44,6 +44,11 @@ public sealed class ResolutionDetails<T>
4444
/// </summary>
4545
public string Variant { get; }
4646

47+
/// <summary>
48+
/// A structure which supports definition of arbitrary properties, with keys of type string, and values of type boolean, string, or number.
49+
/// </summary>
50+
public FlagMetadata FlagMetadata { get; }
51+
4752
/// <summary>
4853
/// Initializes a new instance of the <see cref="ResolutionDetails{T}"/> class.
4954
/// </summary>
@@ -53,15 +58,17 @@ public sealed class ResolutionDetails<T>
5358
/// <param name="reason">Reason</param>
5459
/// <param name="variant">Variant</param>
5560
/// <param name="errorMessage">Error message</param>
61+
/// <param name="flagMetadata">Flag metadata</param>
5662
public ResolutionDetails(string flagKey, T value, ErrorType errorType = ErrorType.None, string reason = null,
57-
string variant = null, string errorMessage = null)
63+
string variant = null, string errorMessage = null, FlagMetadata flagMetadata = null)
5864
{
5965
this.Value = value;
6066
this.FlagKey = flagKey;
6167
this.ErrorType = errorType;
6268
this.Reason = reason;
6369
this.Variant = variant;
6470
this.ErrorMessage = errorMessage;
71+
this.FlagMetadata = flagMetadata;
6572
}
6673
}
6774
}

0 commit comments

Comments
 (0)