Skip to content

Commit d8883e5

Browse files
fix: support mismatched property/source-column types in AddAggregateFunction (#53)
1 parent 1b62ad2 commit d8883e5

7 files changed

Lines changed: 78 additions & 10 deletions

File tree

docs/data-annotations/continuous-aggregates.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public class TradeAggregate
8181
public decimal TotalVolume { get; set; }
8282

8383
[Aggregate(EAggregateFunction.Count, "*")]
84-
public int TradeCount { get; set; }
84+
public long TradeCount { get; set; }
8585
}
8686
```
8787

@@ -232,7 +232,7 @@ public class TradeHourlyAggregate
232232
public decimal TotalVolume { get; set; }
233233

234234
[Aggregate(EAggregateFunction.Count, "*")]
235-
public int TradeCount { get; set; }
235+
public long TradeCount { get; set; }
236236

237237
[Aggregate(EAggregateFunction.First, nameof(Trade.Price))]
238238
public decimal OpeningPrice { get; set; }
@@ -453,7 +453,7 @@ public class TradeHourlyAggregate
453453
public decimal TotalVolume { get; set; }
454454

455455
[Aggregate(EAggregateFunction.Count, "*")]
456-
public int TradeCount { get; set; }
456+
public long TradeCount { get; set; }
457457
}
458458
```
459459

@@ -509,7 +509,7 @@ public class DailySummary
509509
public decimal TotalRevenue { get; set; }
510510

511511
[Aggregate(EAggregateFunction.Count, nameof(OrderEvent.OrderId))]
512-
public int OrderCount { get; set; }
512+
public long OrderCount { get; set; }
513513
}
514514
```
515515

@@ -562,6 +562,6 @@ public class WeatherDaily
562562
public double AvgHumidity { get; set; }
563563

564564
[Aggregate(EAggregateFunction.Count, "*")]
565-
public int ReadingCount { get; set; }
565+
public long ReadingCount { get; set; }
566566
}
567567
```

docs/fluent-api/continuous-aggregates.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -251,7 +251,7 @@ public class TradeAggregate
251251
public decimal MaxPrice { get; set; }
252252
public decimal MinPrice { get; set; }
253253
public decimal TotalVolume { get; set; }
254-
public int TradeCount { get; set; }
254+
public long TradeCount { get; set; }
255255
}
256256
```
257257

samples/Eftdb.Samples.Shared/Configurations/TradeAggregateConfiguration.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ public void Configure(EntityTypeBuilder<TradeAggregate> builder)
1616
.AddAggregateFunction(x => x.AveragePrice, x => x.Price, EAggregateFunction.Avg)
1717
.AddAggregateFunction(x => x.MinPrice, x => x.Price, EAggregateFunction.Max)
1818
.AddAggregateFunction(x => x.MaxPrice, x => x.Price, EAggregateFunction.Min)
19+
.AddAggregateFunction(x => x.TotalVolume, x => x.Size, EAggregateFunction.Sum)
20+
.AddAggregateFunction(x => x.TradeCount, x => x.Timestamp, EAggregateFunction.Count)
1921
.AddGroupByColumn(x => x.Exchange)
2022
.AddGroupByColumn("1, 2")
2123
.Where("\"ticker\" = 'MCRS'")

samples/Eftdb.Samples.Shared/Models/TradeAggregate.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,7 @@ public class TradeAggregate
55
public decimal AveragePrice { get; set; }
66
public decimal MaxPrice { get; set; }
77
public decimal MinPrice { get; set; }
8+
public decimal TotalVolume { get; set; }
9+
public long TradeCount { get; set; }
810
}
911
}

samples/Eftdb.Samples.Shared/Models/WeatherAggregate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public class WeatherAggregate
4545

4646
// Count aggregate function (using "*" for count all records)
4747
[Aggregate(EAggregateFunction.Count, "*")]
48-
public int RecordCount { get; set; }
48+
public long RecordCount { get; set; }
4949

5050
// First aggregate function (gets first temperature value in time bucket)
5151
[Aggregate(EAggregateFunction.First, nameof(WeatherData.Temperature))]

src/Eftdb/Configuration/ContinuousAggregate/ContinuousAggregateBuilder.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,14 +58,15 @@ public ContinuousAggregateBuilder<TEntity, TSourceEntity> MaterializedOnly(bool
5858
/// <summary>
5959
/// Adds an aggregate function mapping between a property on the continuous aggregate and a source column.
6060
/// </summary>
61-
/// <typeparam name="TProperty">The property type.</typeparam>
61+
/// <typeparam name="TProperty">The type of the property on the continuous aggregate.</typeparam>
62+
/// <typeparam name="TSourceProperty">The type of the source column on the hypertable.</typeparam>
6263
/// <param name="propertyExpression">Expression selecting the property on the continuous aggregate.</param>
6364
/// <param name="sourceColumn">Expression selecting the source column from the hypertable.</param>
6465
/// <param name="function">The aggregate function to apply.</param>
6566
/// <returns>The builder for method chaining.</returns>
66-
public ContinuousAggregateBuilder<TEntity, TSourceEntity> AddAggregateFunction<TProperty>(
67+
public ContinuousAggregateBuilder<TEntity, TSourceEntity> AddAggregateFunction<TProperty, TSourceProperty>(
6768
Expression<Func<TEntity, TProperty>> propertyExpression,
68-
Expression<Func<TSourceEntity, TProperty>> sourceColumn,
69+
Expression<Func<TSourceEntity, TSourceProperty>> sourceColumn,
6970
EAggregateFunction function)
7071
{
7172
string propertyName = GetPropertyName(propertyExpression);

tests/Eftdb.Tests/TypeBuilders/ContinuousAggregateBuilderTests.cs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,69 @@ public void AddAggregateFunction_Should_Support_All_Aggregate_Types()
788788

789789
#endregion
790790

791+
#region AddAggregateFunction_Should_Support_Mismatched_Property_And_SourceColumn_Types
792+
793+
private class CountMismatch_TradeEntity
794+
{
795+
public DateTime Timestamp { get; set; }
796+
public string Ticker { get; set; } = string.Empty;
797+
public decimal Price { get; set; }
798+
}
799+
800+
private class CountMismatch_TradeAggregate
801+
{
802+
public DateTime TimeBucket { get; set; }
803+
public int TradeCount { get; set; }
804+
public long TickerCount { get; set; }
805+
}
806+
807+
private class CountMismatch_Context : DbContext
808+
{
809+
public DbSet<CountMismatch_TradeEntity> Trades => Set<CountMismatch_TradeEntity>();
810+
public DbSet<CountMismatch_TradeAggregate> HourlyTrades => Set<CountMismatch_TradeAggregate>();
811+
812+
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
813+
=> optionsBuilder.UseNpgsql("Host=localhost;Database=test;Username=test;Password=test")
814+
.UseTimescaleDb();
815+
816+
protected override void OnModelCreating(ModelBuilder modelBuilder)
817+
{
818+
modelBuilder.Entity<CountMismatch_TradeEntity>(entity =>
819+
{
820+
entity.HasNoKey();
821+
entity.ToTable("Trades");
822+
entity.IsHypertable(x => x.Timestamp);
823+
});
824+
825+
modelBuilder.Entity<CountMismatch_TradeAggregate>(entity =>
826+
{
827+
entity.HasNoKey();
828+
entity.IsContinuousAggregate<CountMismatch_TradeAggregate, CountMismatch_TradeEntity>(
829+
"hourly_trades",
830+
"1 hour",
831+
x => x.Timestamp)
832+
.AddAggregateFunction(x => x.TradeCount, x => x.Timestamp, EAggregateFunction.Count)
833+
.AddAggregateFunction(x => x.TickerCount, x => x.Ticker, EAggregateFunction.Count);
834+
});
835+
}
836+
}
837+
838+
[Fact]
839+
public void AddAggregateFunction_Should_Support_Mismatched_Property_And_SourceColumn_Types()
840+
{
841+
using CountMismatch_Context context = new();
842+
IModel model = GetModel(context);
843+
IEntityType entityType = model.FindEntityType(typeof(CountMismatch_TradeAggregate))!;
844+
845+
List<string>? aggregateFunctions = entityType.FindAnnotation(ContinuousAggregateAnnotations.AggregateFunctions)?.Value as List<string>;
846+
Assert.NotNull(aggregateFunctions);
847+
Assert.Equal(2, aggregateFunctions.Count);
848+
Assert.Contains("TradeCount:Count:Timestamp", aggregateFunctions);
849+
Assert.Contains("TickerCount:Count:Ticker", aggregateFunctions);
850+
}
851+
852+
#endregion
853+
791854
#region AddGroupByColumn_Should_Add_Single_Column_From_Expression
792855

793856
private class AddGroupByColumn_Should_Add_Single_Column_From_Expression_MetricEntity

0 commit comments

Comments
 (0)