chore: initial git load of code space

This commit is contained in:
Thom Lamb
2026-05-12 08:52:33 -05:00
parent 9abada692f
commit 5e467bcc9c
384 changed files with 65960 additions and 2 deletions
@@ -0,0 +1,474 @@
using Strata.SqlTools.SqlBreakdown.Interfaces.Core;
using System.Collections;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Strata.SqlTools.SqlBreakdown.Expressions;
/// <summary>
/// Represents a reference to a property from an input data source, typically used for
/// dynamic data binding in query construction. Used when building queries that reference
/// external data sources by GUID identifiers.
/// </summary>
/// <remarks>
/// This expression type is used in scenarios where data comes from registered data
/// sources (like data tables or dimensions) that are identified by GUIDs. The
/// expression can reference a primary data source and optionally a secondary data source
/// for hierarchical or relational lookups.
/// </remarks>
/// <example>
/// <code language="csharp">
/// // Reference a simple property from a data source
/// var patientName = new InputPropertyExpression(
/// dataSourceGuid: Guid.Parse("41639c8f-fecf-4449-b6e6-53f796c0c3e4"),
/// dataKeyLookup: "PatientName"
/// );
///
/// // Reference a property with a secondary data source (dimension lookup)
/// var patientType = new InputPropertyExpression(
/// dataSourceGuid: Guid.Parse("41639c8f-fecf-4449-b6e6-53f796c0c3e4"),
/// secondaryDataSource: Guid.Parse("6ef6b1f7-a50c-4198-8866-140bb82e2dda"),
/// dataKeyLookup: "PatientTypeRollupName"
/// );
/// </code>
/// </example>
public class InputPropertyExpression : Expression
{
/// <summary>
/// Gets the GUID identifier of the primary data source.
/// </summary>
/// <value>
/// The data source GUID, typically representing a data table or primary data entity.
/// </value>
/// <example>
/// 41639c8f-fecf-4449-b6e6-53f796c0c3e4 - the data table id of PES
/// </example>
public Guid DataSourceGuid { get; }
/// <summary>
/// Gets the optional GUID identifier of a secondary data source.
/// </summary>
/// <value>
/// The secondary data source GUID, typically representing a dimension or lookup table.
/// Null if no secondary source is required.
/// </value>
/// <example>
/// 6ef6b1f7-a50c-4198-8866-140bb82e2dda - the dimension id of the Patient Type
/// Rollup dimension
/// </example>
public Guid? SecondaryDataSource { get; }
/// <summary>
/// Gets the key name used to look up the data value.
/// </summary>
/// <value>
/// The property or column name within the data source.
/// </value>
/// <example>"PatientTypeRollupName"</example>
public string DataKeyLookup { get; }
/// <summary>
/// Initializes a new instance of the <see cref="InputPropertyExpression"/> class
/// with a primary data source.
/// </summary>
/// <param name="dataSourceGuid">The GUID of the primary data source.</param>
/// <param name="dataKeyLookup">The key name for data lookup.</param>
/// <remarks>
/// Example:
/// <code language="csharp">
/// var property = new InputPropertyExpression(
/// Guid.Parse("41639c8f-fecf-4449-b6e6-53f796c0c3e4"),
/// "PatientName");
/// </code>
/// </remarks>
public InputPropertyExpression(Guid dataSourceGuid, string dataKeyLookup) : this(dataSourceGuid, null, dataKeyLookup)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="InputPropertyExpression"/> class
/// with primary and optional secondary data sources.
/// </summary>
/// <param name="dataSourceGuid">The GUID of the primary data source.</param>
/// <param name="secondaryDataSource">
/// The optional GUID of the secondary data source.
/// </param>
/// <param name="dataKeyLookup">The key name for data lookup.</param>
/// <remarks>
/// Example with secondary data source:
/// <code language="csharp">
/// var property = new InputPropertyExpression(
/// Guid.Parse("41639c8f-fecf-4449-b6e6-53f796c0c3e4"),
/// Guid.Parse("6ef6b1f7-a50c-4198-8866-140bb82e2dda"),
/// "PatientTypeRollupName");
/// </code>
/// </remarks>
public InputPropertyExpression(Guid dataSourceGuid, Guid? secondaryDataSource, string dataKeyLookup)
{
DataSourceGuid = dataSourceGuid;
SecondaryDataSource = secondaryDataSource;
DataKeyLookup = dataKeyLookup;
}
public override T Accept<T>(IVisitor<T> visitor)
{
return visitor.VisitInputPropertyExpression(this);
}
}
public class CollectionInputPropertyExpression : InputPropertyExpression
{
public CollectionInputPropertyExpression(Guid dataSourceGuid, Guid secondaryDataSource, string dataKeyLookup)
: base(dataSourceGuid, secondaryDataSource, dataKeyLookup)
{
}
public InputPropertyExpression? ItemProperty { get; }
public override T Accept<T>(IVisitor<T> visitor)
{
throw new NotImplementedException();
}
}
public interface IFlatData : IDictionary<string, object>
{
string RowIdKey { get; }
long RowId { get; }
}
public class MyFlatData : Dictionary<string, object>, IFlatData
{
private readonly Lazy<long> _rowId;
public MyFlatData() : this(new Dictionary<string, object>())
{
}
public MyFlatData(IDictionary<string, object> rawData) : this(rawData, "RowID")
{
}
public MyFlatData(IDictionary<string, object> rawData, string rowIdKey) : base(rawData)
{
RowIdKey = rowIdKey;
_rowId = new Lazy<long>(() => this.GetValue<long>(RowIdKey), false);
}
public string RowIdKey { get; }
public long RowId => _rowId.Value;
}
public class FlatData : IFlatData
{
private readonly IDictionary<string, object> _data;
private readonly Lazy<long> _rowId;
public FlatData() : this(new Dictionary<string, object>(), "RowID")
{
}
public FlatData(IDictionary<string, object> rawData, string rowIdKey)
{
_data = rawData;
RowIdKey = rowIdKey;
_rowId = new Lazy<long>(() => this.GetValue<long>(RowIdKey), false);
}
public string RowIdKey { get; }
public long RowId => _rowId.Value;
public IEnumerator<KeyValuePair<string, object>> GetEnumerator()
{
return _data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable)_data).GetEnumerator();
}
public void Add(KeyValuePair<string, object> item)
{
_data.Add(item);
}
public void Clear()
{
_data.Clear();
}
public bool Contains(KeyValuePair<string, object> item)
{
return _data.Contains(item);
}
public void CopyTo(KeyValuePair<string, object>[] array, int arrayIndex)
{
_data.CopyTo(array, arrayIndex);
}
public bool Remove(KeyValuePair<string, object> item)
{
return _data.Remove(item);
}
public int Count => _data.Count;
public bool IsReadOnly { get; }
public void Add(string key, object value)
{
_data.Add(key, value);
}
public bool ContainsKey(string key)
{
return _data.ContainsKey(key);
}
public bool Remove(string key)
{
throw new NotImplementedException();
}
public bool TryGetValue(string key, out object value)
{
return _data.TryGetValue(key, out value!);
}
public IEnumerable<string> Keys => _data.Keys;
ICollection<object> IDictionary<string, object>.Values => _data.Values;
ICollection<string> IDictionary<string, object>.Keys => _data.Keys;
public IEnumerable<object> Values => _data.Values;
public object this[string key]
{
get => _data[key];
set => _data[key] = value;
}
}
public static class FlatDataUtils
{
private static readonly IFormatProvider _culture = new CultureInfo("en-US");
public static object GetValue(this IFlatData data, string key)
{
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
if (!data.ContainsKey(key))
{
throw new ArgumentException(
$"The specified key is not available. Requested key: [{key}] Available keys: [{string.Join(", ", data.Keys)}]",
nameof(key));
}
var rawValue = data[key];
return rawValue;
}
public static TValue GetValue<TValue>(this IFlatData data, string key)
{
var rawValue = data.GetValue(key);
var convertedValue = (TValue)Convert.ChangeType(rawValue, typeof(TValue), _culture);
return convertedValue;
}
public static IEnumerable<long> GetRowIds(this IEnumerable<IFlatData> data)
{
return data.Select(x => x.RowId);
}
}
public interface IHierarchicalData
{
/// <summary>
/// The DataSource for this level of the Hierarchy
/// </summary>
Guid DataSourceGuid { get; }
/// <summary>
/// The Data at this level of the Hierarchy
/// </summary>
IFlatData Data { get; set; }
/// <summary>
/// Returns all Child Data across all DataSources, or an empty collection if there is no Child Data
/// </summary>
IEnumerable<IHierarchicalData> AllChildData { get; set; }
/// <summary>
/// Checks if this record has Child Data for a particular DataSource
/// </summary>
/// <param name="dataSourceGuid">The DataSource to check</param>
/// <returns>True if any Child Data exists for the DataSource</returns>
bool HasChildData(Guid dataSourceGuid);
/// <summary>
/// Returns the Child Data for the given DataSource
/// </summary>
/// <param name="dataSourceGuid">DataSource identifier for the child data</param>
/// <returns>The Child Data or an empty collection if no child data is set for the DataSource</returns>
IEnumerable<IHierarchicalData> GetChildData(Guid dataSourceGuid);
/// <summary>
/// Attempts to add Child Data. Will check if child data exists before adding.
/// </summary>
/// <param name="datasourceGuid">DataSource identifier for the child data</param>
/// <param name="data">The Child Data to Add to the Record</param>
/// <returns>False if child data exists and was not overriden</returns>
bool TryAddChildData(Guid datasourceGuid, IEnumerable<IHierarchicalData> data);
/// <summary>
/// Add Child Data, will override any existing Child Data for the DataSource
/// </summary>
/// <param name="datasourceGuid">DataSource identifier for the child data</param>
/// <param name="data">The Child Data to Add to the Record</param>
void SetChildData(Guid datasourceGuid, IEnumerable<IHierarchicalData> data);
}
public class HierarchicalData : IHierarchicalData
{
private Dictionary<Guid, List<IHierarchicalData>> _childDataMap;
[JsonConstructor]
public HierarchicalData() : this(Guid.Empty, default!, new List<IHierarchicalData>())
{
}
public HierarchicalData(Guid dataSourceGuid, IFlatData rootData) : this(dataSourceGuid, rootData,
new List<IHierarchicalData>())
{
}
public HierarchicalData(Guid dataSourceGuid, IFlatData rootData, IEnumerable<IHierarchicalData> childData)
{
DataSourceGuid = dataSourceGuid;
Data = rootData;
_childDataMap = childData.GroupBy(x => x.DataSourceGuid).ToDictionary(x => x.Key, x => x.ToList());
}
public Guid DataSourceGuid { get; set; }
public IFlatData Data { get; set; }
public IEnumerable<IHierarchicalData> AllChildData
{
get => _childDataMap.SelectMany(x => x.Value).ToList();
set => _childDataMap = value.GroupBy(x => x.DataSourceGuid).ToDictionary(x => x.Key, x => x.ToList());
}
public bool HasChildData(Guid dataSourceGuid)
{
return _childDataMap.ContainsKey(dataSourceGuid);
}
public IEnumerable<IHierarchicalData> GetChildData(Guid dataSourceGuid)
{
if (HasChildData(dataSourceGuid))
{
return _childDataMap[dataSourceGuid];
}
return new List<IHierarchicalData>();
}
public bool TryAddChildData(Guid datasourceGuid, IEnumerable<IHierarchicalData> data)
{
if (_childDataMap.ContainsKey(datasourceGuid))
{
return false;
}
_childDataMap[datasourceGuid] = data.ToList();
return true;
}
public void SetChildData(Guid datasourceGuid, IEnumerable<IHierarchicalData> data)
{
_childDataMap[datasourceGuid] = data.ToList();
}
public override string? ToString()
{
if (Data?.ContainsKey("DimPatientEnEncounterID") ?? false)
{
return Data["DimPatientEnEncounterID"].ToString();
}
return base.ToString();
}
}
#region Json Converters
public class HierarchicalDataConverter : JsonConverter<IHierarchicalData>
{
public override IHierarchicalData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<HierarchicalData>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, IHierarchicalData value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
public class FlatDataConverter : JsonConverter<IFlatData>
{
public override IFlatData? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return JsonSerializer.Deserialize<MyFlatData>(ref reader, options);
}
public override void Write(Utf8JsonWriter writer, IFlatData value, JsonSerializerOptions options)
{
throw new NotImplementedException();
}
}
public class ObjectToInferredTypesConverter : JsonConverter<object>
{
public override object Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options) => reader.TokenType switch
{
JsonTokenType.True => true,
JsonTokenType.False => false,
JsonTokenType.Number when reader.TryGetInt64(out long l) => l,
JsonTokenType.Number => reader.GetDouble(),
JsonTokenType.String when reader.TryGetDateTime(out DateTime datetime) => datetime,
JsonTokenType.String => reader.GetString()!,
_ => JsonDocument.ParseValue(ref reader).RootElement.Clone()
};
public override void Write(
Utf8JsonWriter writer,
object objectToWrite,
JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, objectToWrite, objectToWrite.GetType(), options);
}
#endregion