Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/publish-nuget.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ jobs:
runs-on: ubuntu-latest
needs: test
env:
CORE_PROJECT_PATH: "CmdScale.EntityFrameworkCore.TimescaleDB/CmdScale.EntityFrameworkCore.TimescaleDB.csproj"
DESIGN_PROJECT_PATH: "CmdScale.EntityFrameworkCore.TimescaleDB.Design/CmdScale.EntityFrameworkCore.TimescaleDB.Design.csproj"
CORE_PROJECT_PATH: "src/TimescaleDB/TimescaleDB.csproj"
DESIGN_PROJECT_PATH: "src/TimescaleDB.Design/TimescaleDB.Design.csproj"

steps:
- name: Checkout repository
Expand Down
184 changes: 134 additions & 50 deletions CmdScale.EntityFrameworkCore.TimescaleDB.sln

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB.Example.DataAccess\CmdScale.EntityFrameworkCore.TimescaleDB.Example.DataAccess.csproj" />
<ProjectReference Include="..\..\samples\Context\Context.Example.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB\CmdScale.EntityFrameworkCore.TimescaleDB.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB\TimescaleDB.csproj" />
</ItemGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB.Example.DataAccess\CmdScale.EntityFrameworkCore.TimescaleDB.Example.DataAccess.csproj" />
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB.Design\CmdScale.EntityFrameworkCore.TimescaleDB.Design.csproj" />
<ProjectReference Include="..\Context\Context.Example.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB.Design\TimescaleDB.Design.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB.Design\CmdScale.EntityFrameworkCore.TimescaleDB.Design.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB.Design\TimescaleDB.Design.csproj" />
</ItemGroup>

<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.8" />
</ItemGroup>
<ItemGroup>
<None Include="..\assets\cmd-nuget-logo.jpg">
<None Include="..\..\assets\cmd-nuget-logo.jpg">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\LICENSE">
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\README.md">
<None Include="..\..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<Content Include="build\**\*" Pack="true" PackagePath="build\" />
<Content Include="build\**\*" Pack="true" PackagePath="buildTransitive\" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB\CmdScale.EntityFrameworkCore.TimescaleDB.csproj" />
<ProjectReference Include="..\TimescaleDB\TimescaleDB.csproj" />
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using CmdScale.EntityFrameworkCore.TimescaleDB.Abstractions;
using CmdScale.EntityFrameworkCore.TimescaleDB.Operations;
using System.Text;

namespace CmdScale.EntityFrameworkCore.TimescaleDB.Generators
{
Expand All @@ -16,54 +17,63 @@ public HypertableOperationGenerator(bool isDesignTime = false)
}

sqlHelper = new SqlBuilderHelper(quoteString);

}

public List<string> Generate(CreateHypertableOperation operation)
{
string qualifiedTableName = sqlHelper.Regclass(operation.TableName, operation.Schema);
string qualifiedIdentifier = sqlHelper.QualifiedIdentifier(operation.TableName, operation.Schema);

List<string> statements =
[
$"SELECT create_hypertable({qualifiedTableName}, '{operation.TimeColumnName}');"
];
List<string> statements = [];
List<string> communityStatements = [];

// ChunkTimeInterval
// Build create_hypertable with chunk_time_interval if provided
var createHypertableCall = new StringBuilder();
createHypertableCall.Append($"SELECT create_hypertable({qualifiedTableName}, '{operation.TimeColumnName}'");

if (!string.IsNullOrEmpty(operation.ChunkTimeInterval))
{
// Check if the interval is a plain number (e.g., for microseconds).
if (long.TryParse(operation.ChunkTimeInterval, out _))
{
// If it's a number, don't wrap it in quotes.
statements.Add($"SELECT set_chunk_time_interval({qualifiedTableName}, {operation.ChunkTimeInterval}::bigint);");
createHypertableCall.Append($", chunk_time_interval => {operation.ChunkTimeInterval}::bigint");
}
else
{
// If it's a string like '7 days', wrap it in quotes.
statements.Add($"SELECT set_chunk_time_interval({qualifiedTableName}, INTERVAL '{operation.ChunkTimeInterval}');");
createHypertableCall.Append($", chunk_time_interval => INTERVAL '{operation.ChunkTimeInterval}'");
}
}

createHypertableCall.Append(");");
statements.Add(createHypertableCall.ToString());

// EnableCompression
// EnableCompression (Community Edition only)
if (operation.EnableCompression || operation.ChunkSkipColumns?.Count > 0)
{
bool enableCompression = operation.EnableCompression || operation.ChunkSkipColumns != null && operation.ChunkSkipColumns.Count > 0;
statements.Add($"ALTER TABLE {qualifiedIdentifier} SET (timescaledb.compress = {enableCompression.ToString().ToLower()});");
communityStatements.Add($"ALTER TABLE {qualifiedIdentifier} SET (timescaledb.compress = {enableCompression.ToString().ToLower()});");
}

// ChunkSkipColumns
// ChunkSkipColumns (Community Edition only)
if (operation.ChunkSkipColumns != null && operation.ChunkSkipColumns.Count > 0)
{
statements.Add("SET timescaledb.enable_chunk_skipping = 'ON';");
communityStatements.Add("SET timescaledb.enable_chunk_skipping = 'ON';");

foreach (string column in operation.ChunkSkipColumns)
{
statements.Add($"SELECT enable_chunk_skipping({qualifiedTableName}, '{column}');");
communityStatements.Add($"SELECT enable_chunk_skipping({qualifiedTableName}, '{column}');");
}
}

// AdditionalDimensions
// Add wrapped community statements if any exist
if (communityStatements.Count > 0)
{
statements.Add(WrapCommunityFeatures(communityStatements));
}

// AdditionalDimensions (Available in both editions)
if (operation.AdditionalDimensions != null && operation.AdditionalDimensions.Count > 0)
{
foreach (Dimension dimension in operation.AdditionalDimensions)
Expand All @@ -88,45 +98,52 @@ public List<string> Generate(AlterHypertableOperation operation)
string qualifiedIdentifier = sqlHelper.QualifiedIdentifier(operation.TableName, operation.Schema);

List<string> statements = [];
List<string> communityStatements = [];

// Check for ChunkTimeInterval change
// Check for ChunkTimeInterval change (Available in both editions)
if (operation.ChunkTimeInterval != operation.OldChunkTimeInterval)
{
var setChunkTimeInterval = new StringBuilder();
setChunkTimeInterval.Append($"SELECT set_chunk_time_interval({qualifiedTableName}, ");

// Check if the interval is a plain number (e.g., for microseconds).
if (long.TryParse(operation.ChunkTimeInterval, out _))
{
// If it's a number, don't wrap it in quotes.
statements.Add($"SELECT set_chunk_time_interval({qualifiedTableName}, {operation.ChunkTimeInterval}::bigint);");
setChunkTimeInterval.Append($"{operation.ChunkTimeInterval}::bigint");
}
else
{
// If it's a string like '7 days', wrap it in quotes.
statements.Add($"SELECT set_chunk_time_interval({qualifiedTableName}, INTERVAL '{operation.ChunkTimeInterval}');");
setChunkTimeInterval.Append($"INTERVAL '{operation.ChunkTimeInterval}'");
}

setChunkTimeInterval.Append(");");
statements.Add(setChunkTimeInterval.ToString());
}

// Check for EnableCompression change
// Check for EnableCompression change (Community Edition only)
bool newCompressionState = operation.EnableCompression || operation.ChunkSkipColumns != null && operation.ChunkSkipColumns.Any();
bool oldCompressionState = operation.OldEnableCompression || operation.OldChunkSkipColumns != null && operation.OldChunkSkipColumns.Any();

if (newCompressionState != oldCompressionState)
{
string compressionValue = newCompressionState.ToString().ToLower();
statements.Add($"ALTER TABLE {qualifiedIdentifier} SET (timescaledb.compress = {compressionValue});");
communityStatements.Add($"ALTER TABLE {qualifiedIdentifier} SET (timescaledb.compress = {compressionValue});");
}

// Handle ChunkSkipColumns
// Handle ChunkSkipColumns (Community Edition only)
IReadOnlyList<string> newColumns = operation.ChunkSkipColumns ?? [];
IReadOnlyList<string> oldColumns = operation.OldChunkSkipColumns ?? [];
List<string> addedColumns = [.. newColumns.Except(oldColumns)];

if (addedColumns.Count != 0)
{
statements.Add("SET timescaledb.enable_chunk_skipping = 'ON';");
communityStatements.Add("SET timescaledb.enable_chunk_skipping = 'ON';");

foreach (string column in addedColumns)
{
statements.Add($"SELECT enable_chunk_skipping({qualifiedTableName}, '{column}');");
communityStatements.Add($"SELECT enable_chunk_skipping({qualifiedTableName}, '{column}');");
}
}

Expand All @@ -135,12 +152,44 @@ public List<string> Generate(AlterHypertableOperation operation)
{
foreach (string column in removedColumns)
{
statements.Add($"SELECT disable_chunk_skipping({qualifiedTableName}, '{column}');");
communityStatements.Add($"SELECT disable_chunk_skipping({qualifiedTableName}, '{column}');");
}
}

// Add wrapped community statements if any exist
if (communityStatements.Count > 0)
{
statements.Add(WrapCommunityFeatures(communityStatements));
}

return statements;
}
}
}

/// <summary>
/// Wraps multiple SQL statements in a single license check block to ensure they only run on Community Edition
/// </summary>
private string WrapCommunityFeatures(List<string> sqlStatements)
{
var sb = new StringBuilder();
sb.AppendLine("DO $");
sb.AppendLine("DECLARE");
sb.AppendLine(" license TEXT;");
sb.AppendLine("BEGIN");
sb.AppendLine(" license := current_setting('timescaledb.license', true);");
sb.AppendLine(" ");
sb.AppendLine(" IF license IS NULL OR license != 'apache' THEN");

foreach (string sql in sqlStatements)
{
sb.AppendLine($" {sql}");
}

sb.AppendLine(" ELSE");
sb.AppendLine(" RAISE WARNING 'Skipping Community Edition features (compression, chunk skipping) - not available in Enterprise Edition';");
sb.AppendLine(" END IF;");
sb.AppendLine("END $;");

return sb.ToString();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,15 @@
<PackageTags>timescaledb;timescale;efcore;ef-core;entityframeworkcore;postgresql;postgres;time-series;timeseries;data;database;efcore-provider;</PackageTags>
</PropertyGroup>
<ItemGroup>
<None Include="..\assets\cmd-nuget-logo.jpg">
<None Include="..\..\assets\cmd-nuget-logo.jpg">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\LICENSE">
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
<None Include="..\README.md">
<None Include="..\..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB.Design\CmdScale.EntityFrameworkCore.TimescaleDB.Design.csproj" />
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB\CmdScale.EntityFrameworkCore.TimescaleDB.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB.Design\TimescaleDB.Design.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB\TimescaleDB.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\CmdScale.EntityFrameworkCore.TimescaleDB\CmdScale.EntityFrameworkCore.TimescaleDB.csproj" />
<ProjectReference Include="..\..\src\TimescaleDB\TimescaleDB.csproj" />
</ItemGroup>

<ItemGroup>
Expand Down
Loading