Skip to content

Commit

Permalink
Merge pull request #2789 from FirelyTeam/feature/metrics-service
Browse files Browse the repository at this point in the history
IMetricService implementation
  • Loading branch information
mmsmits authored May 28, 2024
2 parents 77ff5d4 + ee66ac3 commit 1d6d91b
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 22 deletions.
2 changes: 1 addition & 1 deletion build/pipeline-variables.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ variables:
isTagBranch: $[startswith(variables['Build.SourceBranch'], 'refs/tags/v')]
GITHUB_PACKAGES_APIKEY: $(GitHubPushPackagesAPIKey) # key is set in variable group APIKeys
NUGET_APIKEY: $(NuGetSDKAPIKey) # key is set in variable group APIKeys
useGitHubPackageFeed: 'no' # possible values: 'yes', 'no'
useGitHubPackageFeed: 'yes' # possible values: 'yes', 'no'
14 changes: 12 additions & 2 deletions src/Hl7.Fhir.Base/ElementModel/Types/Quantity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,12 @@ internal static Result<Quantity> Multiply(Quantity a, Quantity b)
{
var (left, right) = alignQuantityUnits(a, b);

return Ok<Quantity>(new(left.Value * right.Value, Ucum.PerformMetricOperation(left.Unit, right.Unit, (a, b) => a * b)));
if (!left.TryMultiply(right, out var result))
{
return Fail<Quantity>(Error.InvalidOperation($"The multiply operation cannot be performed on quantities with units '{left.Unit}' and '{right.Unit}'."));
}

return Ok(result);
}

internal static Result<Quantity> Divide(Quantity a, Quantity b)
Expand All @@ -369,7 +374,12 @@ internal static Result<Quantity> Divide(Quantity a, Quantity b)

var (left, right) = alignQuantityUnits(a, b);

return Ok<Quantity>(new(left.Value / right.Value, left.Unit == right.Unit ? "1" : Ucum.PerformMetricOperation(left.Unit, right.Unit, (a, b) => a / b)));
if (!left.TryDivide(right, out var result))
{
return Fail<Quantity>(Error.InvalidOperation($"The divide operation cannot be performed on quantities with units '{left.Unit}' and '{right.Unit}'."));
}

return Ok(result);
}

public override int GetHashCode() => (Unit, Value).GetHashCode();
Expand Down
89 changes: 71 additions & 18 deletions src/Hl7.Fhir.Base/ElementModel/Types/Ucum.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,24 @@

#nullable enable


using Fhir.Metrics;
using M = Fhir.Metrics;
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using M = Fhir.Metrics;
using System.Globalization;

namespace Hl7.Fhir.ElementModel.Types
{
public static class MetricConfiguration
{
[CLSCompliant(false)]
public static Lazy<IMetricService> MetricService { get; set; } = new(() => FhirMetricService.Instance.Value);
}

internal static class Ucum
{
private static readonly Lazy<SystemOfUnits> SYSTEM = new(() => UCUM.Load());
private static readonly IMetricService METRIC_SERVICE = MetricConfiguration.MetricService.Value;

/// <summary>
/// Try to canonicalize the system type quantity to Umum base quantity. So a 1,000 cm will be 10 m. Or an inch will be converted to a meter.
Expand All @@ -29,31 +35,78 @@ internal static class Ucum
/// <returns><c>true</c> when the conversion succeeded. Or <c>false</c> otherwise.</returns>
internal static bool TryCanonicalize(this Quantity quantity, [NotNullWhen(true)] out Quantity? canonicalizedQuantity)
{
try
{
M.Quantity metricsQuantity = quantity.Value.toUnitsOfMeasureQuantity(quantity.Unit);
metricsQuantity = SYSTEM.Value.Canonical(metricsQuantity);
canonicalizedQuantity = new(metricsQuantity.Value.ToDecimal(), metricsQuantity.Metric.ToString(), QuantityUnitSystem.UCUM);
return true;
}
catch (Exception ex) when (ex is ArgumentException or InvalidCastException)
var qtyTuple = (
quantity.Value.ToString(CultureInfo.InvariantCulture),
quantity.Unit,
quantity.System == QuantityUnitSystem.UCUM ? "http://unitsofmeasure.org" : ""
);

if (!METRIC_SERVICE.TryCanonicalize(qtyTuple, out var canonicalized))
{
canonicalizedQuantity = null;
return false;
}

canonicalizedQuantity = quantityFromTuple(canonicalized!.Value);

return true;
}

internal static bool TryMultiply(this Quantity quantity, Quantity multiplier, [NotNullWhen(true)] out Quantity? result)
{
var qty1 = (
quantity.Value.ToString(CultureInfo.InvariantCulture),
quantity.Unit,
quantity.System == QuantityUnitSystem.UCUM ? "http://unitsofmeasure.org" : ""
);
var qty2 = (
multiplier.Value.ToString(CultureInfo.InvariantCulture),
multiplier.Unit,
multiplier.System == QuantityUnitSystem.UCUM ? "http://unitsofmeasure.org" : ""
);

if (!METRIC_SERVICE.TryMultiply(qty1, qty2, out var resultTuple))
{
result = null;
return false;
}

private static M.Quantity toUnitsOfMeasureQuantity(this decimal value, string? unit)
result = quantityFromTuple(resultTuple!.Value);

return true;
}

internal static bool TryDivide(this Quantity quantity, Quantity divisor, [NotNullWhen(true)] out Quantity? result)
{
Metric metric = (unit != null) ? SYSTEM.Value.Metric(unit) : new Metric(new List<Metric.Axis>());
return new M.Quantity(value, metric);
var qty1 = (
quantity.Value.ToString(CultureInfo.InvariantCulture),
quantity.Unit,
quantity.System == QuantityUnitSystem.UCUM ? "http://unitsofmeasure.org" : ""
);
var qty2 = (
divisor.Value.ToString(CultureInfo.InvariantCulture),
divisor.Unit,
divisor.System == QuantityUnitSystem.UCUM ? "http://unitsofmeasure.org" : ""
);

if (!METRIC_SERVICE.TryDivide(qty1, qty2, out var resultTuple))
{
result = null;
return false;
}

result = quantityFromTuple(resultTuple!.Value);

return true;
}

internal static string PerformMetricOperation(string unit1, string unit2, Func<Metric, Metric, Metric> operation)
private static Quantity quantityFromTuple((string value, string unit, string codesystem) quantity)
{
var a = SYSTEM.Value.Metric(unit1);
var b = SYSTEM.Value.Metric(unit2);
return operation(a, b).ToString();
return new Quantity(
decimal.Parse(quantity.value, NumberStyles.Any, CultureInfo.InvariantCulture),
quantity.unit == "" ? "1" : quantity.unit,
QuantityUnitSystem.UCUM
);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/Hl7.Fhir.Base.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="Fhir.Metrics" Version="1.2.2" />
<PackageReference Include="Fhir.Metrics" Version="1.3.0-build-20240523.2" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Reflection.Emit.Lightweight" Version="4.7.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
Expand Down

0 comments on commit 1d6d91b

Please sign in to comment.