Skip to content

Commit

Permalink
Merge pull request #94 from ARKlab/feature/18962-AddUpdateDerivedCurv…
Browse files Browse the repository at this point in the history
…eCfg

feat(updatederivedcfg): Added UpdateDerivedCfg
  • Loading branch information
jacopocinaark authored Jan 8, 2025
2 parents ae46b9b + 505a04e commit 833df16
Show file tree
Hide file tree
Showing 15 changed files with 308 additions and 60 deletions.
2 changes: 1 addition & 1 deletion Artesian/Artesian.SDK.Tests/ActualTimeSerieQueries.cs
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public async Task ActWithCustomHeaderFormatCheck()
.InRelativePeriodRange(Period.FromWeeks(2), Period.FromDays(20))
.ExecuteAsync();

var headerXAgent = httpTest.CallLog.FirstOrDefault().Request.Headers.FirstOrDefault(w => w.Name == "X-Artesian-Agent");
var headerXAgent = httpTest.CallLog.FirstOrDefault().Request.Headers.FirstOrDefault(w => string.Equals(w.Name, "X-Artesian-Agent"));

//ArtesianSDK-C#: 2.2.1.0,Win32NT: 10.0.19041.0,.NETFramework: 4.6.1

Expand Down
5 changes: 5 additions & 0 deletions Artesian/Artesian.SDK.Tests/Samples/DeleteTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public class DeleteTest

[Test]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
public async Task DeleteActual()
{
var qs = new QueryService(_cfg);
Expand Down Expand Up @@ -94,6 +95,7 @@ public async Task DeleteActual()

[Test]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
public async Task DeleteVersion()
{
var qs = new QueryService(_cfg);
Expand Down Expand Up @@ -169,6 +171,7 @@ public async Task DeleteVersion()

[Test]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
public async Task DeleteAuction()
{
var qs = new QueryService(_cfg);
Expand Down Expand Up @@ -249,6 +252,7 @@ public async Task DeleteAuction()
}

[Test]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
public async Task DeleteMAS()
{
Expand Down Expand Up @@ -358,6 +362,7 @@ public async Task DeleteMAS()
}

[Test]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
public async Task DeleteBidAsk()
{
Expand Down
30 changes: 29 additions & 1 deletion Artesian/Artesian.SDK.Tests/Samples/DerivedTimeSerieTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ namespace Artesian.SDK.Tests.Samples
public class DerivedTimeSerieTest
{
private readonly ArtesianServiceConfig _cfg = new ArtesianServiceConfig(new Uri("https://arkive.artesian.cloud/tenantName/"), "APIKey");

[Test]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
public async Task CreateDerivedCoalesceTimeSeries()
{
var qs = new QueryService(_cfg);
Expand Down Expand Up @@ -133,6 +134,32 @@ public async Task CreateDerivedCoalesceTimeSeries()
ClassicAssert.AreEqual(200, item.Value);
}

// Update DerivedCfg
curveIds.Reverse();
var derivedCfgUpdate = new DerivedCfgCoalesce()
{
OrderedReferencedMarketDataIds = curveIds.ToArray(),
};

marketData.UpdateDerivedConfiguration(derivedCfgUpdate, false).ConfigureAwait(true).GetAwaiter().GetResult();

await Task.Delay(2000);

ts = await qs.CreateActual()
.ForMarketData(new[] { marketData.MarketDataId.Value })
.InGranularity(Granularity.Day)
.InAbsoluteDateRange(new LocalDate(2018, 10, 01), new LocalDate(2018, 10, 10))
.ExecuteAsync();

foreach (var item in ts)
{
if (item.Time.Date <= new DateTime(2018, 10, 3))
ClassicAssert.AreEqual(100, item.Value);

if (item.Time.Date > new DateTime(2018, 10, 3))
ClassicAssert.AreEqual(200, item.Value);
}

/*******************************************************************
* Tidy Up
*******************************************************************/
Expand All @@ -146,6 +173,7 @@ public async Task CreateDerivedCoalesceTimeSeries()

[Test]
[Ignore("Run only manually with proper artesian URI and ApiKey set")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Design", "MA0051:Method is too long", Justification = "<Pending>")]
public async Task CreateDerivedSumTimeSeries()
{
var qs = new QueryService(_cfg);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ protected override DerivedCfgBase Create(Type objectType, JObject jObject)

if (token.ToObject<DerivedAlgorithm>() == DerivedAlgorithm.Sum)
{
throw new NotSupportedException($@"Not yet impletemented DerivedAlgorithm {DerivedAlgorithm.Sum}");
return new DerivedCfgSum();
}

if (token.ToObject<DerivedAlgorithm>() == DerivedAlgorithm.Coalesce)
Expand Down Expand Up @@ -49,6 +49,7 @@ protected override Type GetType(DerivedAlgorithm discriminatorValue)
{
DerivedAlgorithm.MUV => typeof(DerivedCfgMuv),
DerivedAlgorithm.Coalesce => typeof(DerivedCfgCoalesce),
DerivedAlgorithm.Sum => typeof(DerivedCfgSum),
_ => null,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@

namespace Artesian.SDK.Dto.DerivedCfg.Serialize
{
internal abstract class JsonPolymorphicConverter<TBase, TDiscriminatorEnum> : JsonConverter<TBase> where TDiscriminatorEnum : struct, Enum
internal abstract class JsonPolymorphicConverter<TBase, TDiscriminatorEnum> : JsonConverter<TBase>
where TDiscriminatorEnum : struct, Enum
{
private readonly string _discriminatorPropertyName;

Expand All @@ -22,35 +23,44 @@ protected JsonPolymorphicConverter(string discriminatorPropertyName)
throw new JsonException();
}

using JsonDocument jsonDocument = JsonDocument.ParseValue(ref reader);
string propertyName = options.PropertyNamingPolicy?.ConvertName(_discriminatorPropertyName) ?? _discriminatorPropertyName;
if (!jsonDocument.RootElement.TryGetProperty(propertyName, out var value))
using (var jsonDocument = JsonDocument.ParseValue(ref reader))
{
throw new JsonException();
}
var pn = options.PropertyNamingPolicy?.ConvertName(_discriminatorPropertyName) ?? _discriminatorPropertyName;

Type type = null;
TDiscriminatorEnum result;
if (value.ValueKind == JsonValueKind.Number && value.TryGetInt32(out var value2) && Enum.IsDefined(typeof(TDiscriminatorEnum), value2))
{
type = GetType((TDiscriminatorEnum)Enum.ToObject(typeof(TDiscriminatorEnum), value2));
}
else if (value.ValueKind == JsonValueKind.String && Enum.TryParse<TDiscriminatorEnum>(value.GetString(), ignoreCase: true, out result))
{
type = GetType(result);
}
if (!jsonDocument.RootElement.TryGetProperty(pn, out var typeProperty))
{
throw new JsonException();
}

if (type == null)
{
throw new JsonException();
}
Type? type = null;

if (typeProperty.ValueKind == JsonValueKind.Number
&& typeProperty.TryGetInt32(out var enumInt)
&& Enum.IsDefined(typeof(TDiscriminatorEnum), enumInt))
{
type = GetType((TDiscriminatorEnum)Enum.ToObject(typeof(TDiscriminatorEnum), enumInt));
}
else if (typeProperty.ValueKind == JsonValueKind.String
&& Enum.TryParse<TDiscriminatorEnum>(typeProperty.GetString(), true, out var enumVal))
{
type = GetType(enumVal);
}

return (TBase)JsonSerializer.Deserialize(jsonDocument.RootElement.GetRawText(), type, options);
if (type == null)
{
throw new JsonException();
}

var jsonObject = jsonDocument.RootElement.GetRawText();
var result = (TBase?)JsonSerializer.Deserialize(jsonObject, type, options);

return result;
}
}

public override void Write(Utf8JsonWriter writer, TBase value, JsonSerializerOptions options)
{
JsonSerializer.Serialize(writer, (object)value, options);
JsonSerializer.Serialize(writer, (object?)value, options);
}
}
}
}
23 changes: 1 addition & 22 deletions Artesian/Artesian.SDK/Dto/MarketData/MarketDataEntity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public Input(MarketDataEntity.Output output)
/// The custom Tags assigned to the data
/// </summary>
[MessagePack.Key(10)]
public Dictionary<string, List<string>> Tags { get; set; }
public IDictionary<string, List<string>> Tags { get; set; }
/// <summary>
/// The Authorization Path
/// </summary>
Expand Down Expand Up @@ -232,25 +232,4 @@ public class WithRange : Output
public IEnumerable<CurveRange> Curves { get; set; }
}
}

internal static class MarketDataEntityInputExt
{
public static void ValidateRegister(this MarketDataEntity.Input marketDataEntityInput)
{
if (marketDataEntityInput.MarketDataId != 0)
throw new ArgumentException("MarketDataId must be 0", nameof(marketDataEntityInput));

if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.TransformID != null)
throw new ArgumentException("No transform possible when Type is MarketAssessment", nameof(marketDataEntityInput));
}

public static void ValidateUpdate(this MarketDataEntity.Input marketDataEntityInput)
{
if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.TransformID != null)
throw new ArgumentException("No transform possible when Type is MarketAssessment", nameof(marketDataEntityInput));

if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.AggregationRule != AggregationRule.Undefined)
throw new ArgumentException("Aggregation Rule must be Undefined if Type is MarketAssessment", nameof(marketDataEntityInput));
}
}
}
40 changes: 40 additions & 0 deletions Artesian/Artesian.SDK/Dto/MarketData/MarketDataEntityInputExt.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Artesian.SDK.Dto.DerivedCfg;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Artesian.SDK.Dto.MarketData
{
internal static class MarketDataEntityInputExt
{
public static void ValidateRegister(this MarketDataEntity.Input marketDataEntityInput)
{
if (marketDataEntityInput.MarketDataId != 0)
throw new ArgumentException("MarketDataId must be 0", nameof(marketDataEntityInput));

if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.TransformID != null)
throw new ArgumentException("No transform possible when Type is MarketAssessment", nameof(marketDataEntityInput));
}

public static void ValidateUpdate(this MarketDataEntity.Input marketDataEntityInput)
{
if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.TransformID != null)
throw new ArgumentException("No transform possible when Type is MarketAssessment", nameof(marketDataEntityInput));

if (marketDataEntityInput.Type == MarketDataType.MarketAssessment && marketDataEntityInput.AggregationRule != AggregationRule.Undefined)
throw new ArgumentException("Aggregation Rule must be Undefined if Type is MarketAssessment", nameof(marketDataEntityInput));
}

public static void ValidateDerivedCfg(this MarketDataEntity.Output marketDataEntityOutput, DerivedCfgBase derivedCfg)
{
if (marketDataEntityOutput.DerivedCfg == null)
throw new ArgumentException("Derived Configuration is null for the MarketData selected", nameof(marketDataEntityOutput));

if (marketDataEntityOutput.DerivedCfg.DerivedAlgorithm != derivedCfg.DerivedAlgorithm)
throw new ArgumentException("Derived Algorithm is different from the one in the update", nameof(marketDataEntityOutput));
}
}
}
53 changes: 53 additions & 0 deletions Artesian/Artesian.SDK/Factory/IMarketData.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using Artesian.SDK.Dto;
using Artesian.SDK.Dto.DerivedCfg;

using NodaTime;

using System.Collections.Generic;
Expand Down Expand Up @@ -110,6 +112,57 @@ public interface IMarketData
/// </remarks>
/// <returns> Marketdata </returns>
IBidAskWritable EditBidAsk();

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgMuv derivedCfg, CancellationToken ctk = default);

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="force">Force the update of configuration also if another rebuild process is running (Defualt=false)</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgMuv derivedCfg, bool force = false, CancellationToken ctk = default);

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgCoalesce derivedCfg, CancellationToken ctk = default);

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="force">Force the update of configuration also if another rebuild process is running (Defualt=false)</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgCoalesce derivedCfg, bool force = false, CancellationToken ctk = default);

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgSum derivedCfg, CancellationToken ctk = default);

/// <summary>
/// Update Derived Configuration
/// </summary>
/// <param name="derivedCfg">The Derived Configuration Muv to be updated</param>
/// <param name="force">Force the update of configuration also if another rebuild process is running (Defualt=false)</param>
/// <param name="ctk">Cancellation Token</param>
/// <returns></returns>
Task UpdateDerivedConfiguration(DerivedCfgSum derivedCfg, bool force = false, CancellationToken ctk = default);
}

/// <summary>
Expand Down
Loading

0 comments on commit 833df16

Please sign in to comment.