-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[FEATURE] Implement Tracking in .NET #309
Signed-off-by: christian.lutnik <[email protected]>
- Loading branch information
Showing
8 changed files
with
505 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
|
||
namespace OpenFeature.Model; | ||
|
||
/// <summary> | ||
/// The `tracking event details` structure defines optional data pertinent to a particular `tracking event`. | ||
/// </summary> | ||
/// <seealso href="https://github.com/open-feature/spec/blob/main/specification/sections/06-tracking.md#62-tracking-event-details"/> | ||
public sealed class TrackingEventDetails | ||
{ | ||
/// <summary> | ||
/// The index for the "targeting key" property when the EvaluationContext is serialized or expressed as a dictionary. | ||
/// </summary> | ||
internal const string TargetingKeyIndex = "targetingKey"; | ||
|
||
/// <summary> | ||
///A predefined value field for the tracking details. | ||
/// </summary> | ||
public readonly double? Value; | ||
|
||
private readonly Structure _structure; | ||
|
||
/// <summary> | ||
/// Internal constructor used by the builder. | ||
/// </summary> | ||
/// <param name="content"></param> | ||
/// <param name="value"></param> | ||
internal TrackingEventDetails(Structure content, double? value) | ||
{ | ||
this.Value = value; | ||
this._structure = content; | ||
} | ||
|
||
|
||
/// <summary> | ||
/// Private constructor for making an empty <see cref="TrackingEventDetails"/>. | ||
/// </summary> | ||
private TrackingEventDetails() | ||
{ | ||
this._structure = Structure.Empty; | ||
this.Value = null; | ||
} | ||
|
||
/// <summary> | ||
/// Empty tracking event details. | ||
/// </summary> | ||
public static TrackingEventDetails Empty { get; } = new(); | ||
|
||
|
||
/// <summary> | ||
/// Gets the Value at the specified key | ||
/// </summary> | ||
/// <param name="key">The key of the value to be retrieved</param> | ||
/// <returns>The <see cref="Model.Value"/> associated with the key</returns> | ||
/// <exception cref="KeyNotFoundException"> | ||
/// Thrown when the context does not contain the specified key | ||
/// </exception> | ||
/// <exception cref="ArgumentNullException"> | ||
/// Thrown when the key is <see langword="null" /> | ||
/// </exception> | ||
public Value GetValue(string key) => this._structure.GetValue(key); | ||
|
||
/// <summary> | ||
/// Bool indicating if the specified key exists in the evaluation context | ||
/// </summary> | ||
/// <param name="key">The key of the value to be checked</param> | ||
/// <returns><see cref="bool" />indicating the presence of the key</returns> | ||
/// <exception cref="ArgumentNullException"> | ||
/// Thrown when the key is <see langword="null" /> | ||
/// </exception> | ||
public bool ContainsKey(string key) => this._structure.ContainsKey(key); | ||
|
||
/// <summary> | ||
/// Gets the value associated with the specified key | ||
/// </summary> | ||
/// <param name="value">The <see cref="Model.Value"/> or <see langword="null" /> if the key was not present</param> | ||
/// <param name="key">The key of the value to be retrieved</param> | ||
/// <returns><see cref="bool" />indicating the presence of the key</returns> | ||
/// <exception cref="ArgumentNullException"> | ||
/// Thrown when the key is <see langword="null" /> | ||
/// </exception> | ||
public bool TryGetValue(string key, out Value? value) => this._structure.TryGetValue(key, out value); | ||
|
||
/// <summary> | ||
/// Gets all values as a Dictionary | ||
/// </summary> | ||
/// <returns>New <see cref="IDictionary{TKey,TValue}"/> representation of this Structure</returns> | ||
public IImmutableDictionary<string, Value> AsDictionary() | ||
{ | ||
return this._structure.AsDictionary(); | ||
} | ||
|
||
/// <summary> | ||
/// Return a count of all values | ||
/// </summary> | ||
public int Count => this._structure.Count; | ||
|
||
/// <summary> | ||
/// Returns the targeting key for the context. | ||
/// </summary> | ||
public string? TargetingKey | ||
{ | ||
get | ||
{ | ||
this._structure.TryGetValue(TargetingKeyIndex, out Value? targetingKey); | ||
return targetingKey?.AsString; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Return an enumerator for all values | ||
/// </summary> | ||
/// <returns>An enumerator for all values</returns> | ||
public IEnumerator<KeyValuePair<string, Value>> GetEnumerator() | ||
{ | ||
return this._structure.GetEnumerator(); | ||
} | ||
|
||
/// <summary> | ||
/// Get a builder which can build an <see cref="EvaluationContext"/>. | ||
/// </summary> | ||
/// <returns>The builder</returns> | ||
public static TrackingEventDetailsBuilder Builder() | ||
{ | ||
return new TrackingEventDetailsBuilder(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
using System; | ||
|
||
namespace OpenFeature.Model | ||
{ | ||
/// <summary> | ||
/// A builder which allows the specification of attributes for an <see cref="TrackingEventDetails"/>. | ||
/// <para> | ||
/// A <see cref="TrackingEventDetailsBuilder"/> object is intended for use by a single thread and should not be used | ||
/// from multiple threads. Once an <see cref="TrackingEventDetails"/> has been created it is immutable and safe for use | ||
/// from multiple threads. | ||
/// </para> | ||
/// </summary> | ||
public sealed class TrackingEventDetailsBuilder | ||
{ | ||
private readonly StructureBuilder _attributes = Structure.Builder(); | ||
private double? _value; | ||
|
||
/// <summary> | ||
/// Internal to only allow direct creation by <see cref="TrackingEventDetails.Builder()"/>. | ||
/// </summary> | ||
internal TrackingEventDetailsBuilder() { } | ||
|
||
/// <summary> | ||
/// Set the predefined value field for the tracking details. | ||
/// </summary> | ||
/// <param name="value"></param> | ||
/// <returns></returns> | ||
public TrackingEventDetailsBuilder SetValue(double? value) | ||
{ | ||
this._value = value; | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the targeting key for the tracking details. | ||
/// </summary> | ||
/// <param name="targetingKey">The targeting key</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder SetTargetingKey(string targetingKey) | ||
{ | ||
this._attributes.Set(TrackingEventDetails.TargetingKeyIndex, targetingKey); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given <see cref="Value"/>. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, Value value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given string. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, string value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given int. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, int value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given double. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, double value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given long. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, long value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given bool. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, bool value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given <see cref="Structure"/>. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, Structure value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Set the key to the given DateTime. | ||
/// </summary> | ||
/// <param name="key">The key for the value</param> | ||
/// <param name="value">The value to set</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Set(string key, DateTime value) | ||
{ | ||
this._attributes.Set(key, value); | ||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Incorporate existing tracking details into the builder. | ||
/// <para> | ||
/// Any existing keys in the builder will be replaced by keys in the tracking details. | ||
/// </para> | ||
/// </summary> | ||
/// <param name="trackingDetails">The tracking details to add merge</param> | ||
/// <returns>This builder</returns> | ||
public TrackingEventDetailsBuilder Merge(TrackingEventDetails trackingDetails) | ||
{ | ||
foreach (var kvp in trackingDetails) | ||
{ | ||
this.Set(kvp.Key, kvp.Value); | ||
} | ||
|
||
return this; | ||
} | ||
|
||
/// <summary> | ||
/// Build an immutable <see cref="TrackingEventDetails"/>. | ||
/// </summary> | ||
/// <returns>An immutable <see cref="TrackingEventDetails"/></returns> | ||
public TrackingEventDetails Build() | ||
{ | ||
return new TrackingEventDetails(this._attributes.Build(), this._value); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.