< Summary

Line coverage
84%
Covered lines: 168
Uncovered lines: 32
Coverable lines: 200
Total lines: 262
Line coverage: 84%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
File 1: .ctor(...)100%11100%
File 1: Up(...)100%11100%
File 1: Down(...)100%210%
File 2: BuildTargetModel(...)100%11100%

File(s)

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore.SqlServer/Migrations/Labels/20260913133317_PerTenantLabelUniqueness.cs

#LineLine coverage
 1using Microsoft.EntityFrameworkCore.Migrations;
 2
 3#nullable disable
 4
 5namespace Elsa.Persistence.EFCore.SqlServer.Migrations.Labels
 6{
 7    /// <inheritdoc />
 8    public partial class PerTenantLabelUniqueness : Migration
 9    {
 10        private readonly Elsa.Persistence.EFCore.IElsaDbContextSchema _schema;
 11
 12        /// <inheritdoc />
 313        public PerTenantLabelUniqueness(Elsa.Persistence.EFCore.IElsaDbContextSchema schema)
 14        {
 315            _schema = schema;
 316        }
 17
 18        /// <inheritdoc />
 19        protected override void Up(MigrationBuilder migrationBuilder)
 20        {
 21            // Default tenant is "" (not null). Stamp leftover nulls so the filtered unique
 22            // index (TenantId IS NOT NULL) covers them. Duplicates are not deleted.
 323            migrationBuilder.Sql($"""
 324                UPDATE [{_schema.Schema}].[Labels]
 325                SET [TenantId] = N''
 326                WHERE [TenantId] IS NULL;
 327                """);
 28
 29            // No silent dedupe. List leftover keys and abort; operators must resolve them before upgrading.
 330            migrationBuilder.Sql($"""
 331                IF EXISTS (
 332                    SELECT 1
 333                    FROM [{_schema.Schema}].[Labels]
 334                    GROUP BY [TenantId], [NormalizedName]
 335                    HAVING COUNT(*) > 1
 336                )
 337                BEGIN
 338                    DECLARE @DuplicateKeys nvarchar(max);
 339
 340                    SELECT @DuplicateKeys = STRING_AGG(
 341                        CAST(CONCAT(N'(', ISNULL([TenantId], N'<null>'), N', ', [NormalizedName], N')') AS nvarchar(max)
 342                        N'; '
 343                    )
 344                    FROM (
 345                        SELECT [TenantId], [NormalizedName]
 346                        FROM [{_schema.Schema}].[Labels]
 347                        GROUP BY [TenantId], [NormalizedName]
 348                        HAVING COUNT(*) > 1
 349                    ) AS Duplicates;
 350
 351                    DECLARE @ErrorMessage nvarchar(2048);
 352                    SET @ErrorMessage = CONCAT(
 353                        N'Cannot create unique index IX_Label_TenantId_NormalizedName because leftover duplicate (Tenant
 354                        LEFT(@DuplicateKeys, 1500)
 355                    );
 356                    THROW 50001, @ErrorMessage, 1;
 357                END
 358                """);
 59
 60            // Name/NormalizedName are not truncated; list over-length Ids and abort before ALTER.
 361            migrationBuilder.Sql($"""
 362                IF EXISTS (
 363                    SELECT 1
 364                    FROM [{_schema.Schema}].[Labels]
 365                    WHERE LEN([Name]) > 255 OR LEN([NormalizedName]) > 255
 366                )
 367                BEGIN
 368                    DECLARE @OverLengthIds nvarchar(max);
 369
 370                    SELECT @OverLengthIds = STRING_AGG(CAST([Id] AS nvarchar(max)), N', ')
 371                    FROM [{_schema.Schema}].[Labels]
 372                    WHERE LEN([Name]) > 255 OR LEN([NormalizedName]) > 255;
 373
 374                    DECLARE @ErrorMessage nvarchar(2048);
 375                    SET @ErrorMessage = CONCAT(
 376                        N'Cannot alter Labels.Name / Labels.NormalizedName to nvarchar(255) because leftover rows exceed
 377                        LEFT(@OverLengthIds, 1500)
 378                    );
 379                    THROW 50002, @ErrorMessage, 1;
 380                END
 381                """);
 82
 383            migrationBuilder.AlterColumn<string>(
 384                name: "TenantId",
 385                schema: _schema.Schema,
 386                table: "Labels",
 387                type: "nvarchar(450)",
 388                nullable: true,
 389                oldClrType: typeof(string),
 390                oldType: "nvarchar(max)",
 391                oldNullable: true);
 92
 393            migrationBuilder.AlterColumn<string>(
 394                name: "Name",
 395                schema: _schema.Schema,
 396                table: "Labels",
 397                type: "nvarchar(255)",
 398                maxLength: 255,
 399                nullable: false,
 3100                oldClrType: typeof(string),
 3101                oldType: "nvarchar(max)");
 102
 3103            migrationBuilder.AlterColumn<string>(
 3104                name: "NormalizedName",
 3105                schema: _schema.Schema,
 3106                table: "Labels",
 3107                type: "nvarchar(255)",
 3108                maxLength: 255,
 3109                nullable: false,
 3110                oldClrType: typeof(string),
 3111                oldType: "nvarchar(max)");
 112
 3113            migrationBuilder.CreateIndex(
 3114                name: "IX_Label_TenantId_NormalizedName",
 3115                schema: _schema.Schema,
 3116                table: "Labels",
 3117                columns: new[] { "TenantId", "NormalizedName" },
 3118                unique: true,
 3119                filter: "[TenantId] IS NOT NULL");
 3120        }
 121
 122        /// <inheritdoc />
 123        protected override void Down(MigrationBuilder migrationBuilder)
 124        {
 0125            migrationBuilder.DropIndex(
 0126                name: "IX_Label_TenantId_NormalizedName",
 0127                schema: _schema.Schema,
 0128                table: "Labels");
 129
 0130            migrationBuilder.AlterColumn<string>(
 0131                name: "TenantId",
 0132                schema: _schema.Schema,
 0133                table: "Labels",
 0134                type: "nvarchar(max)",
 0135                nullable: true,
 0136                oldClrType: typeof(string),
 0137                oldType: "nvarchar(450)",
 0138                oldNullable: true);
 139
 0140            migrationBuilder.AlterColumn<string>(
 0141                name: "NormalizedName",
 0142                schema: _schema.Schema,
 0143                table: "Labels",
 0144                type: "nvarchar(max)",
 0145                nullable: false,
 0146                oldClrType: typeof(string),
 0147                oldType: "nvarchar(255)",
 0148                oldMaxLength: 255);
 149
 0150            migrationBuilder.AlterColumn<string>(
 0151                name: "Name",
 0152                schema: _schema.Schema,
 0153                table: "Labels",
 0154                type: "nvarchar(max)",
 0155                nullable: false,
 0156                oldClrType: typeof(string),
 0157                oldType: "nvarchar(255)",
 0158                oldMaxLength: 255);
 0159        }
 160    }
 161}

/home/runner/work/elsa-core/elsa-core/src/modules/Elsa.Persistence.EFCore.SqlServer/Migrations/Labels/20260913133317_PerTenantLabelUniqueness.Designer.cs

#LineLine coverage
 1// <auto-generated />
 2using Elsa.Persistence.EFCore.Modules.Labels;
 3using Microsoft.EntityFrameworkCore;
 4using Microsoft.EntityFrameworkCore.Infrastructure;
 5using Microsoft.EntityFrameworkCore.Metadata;
 6using Microsoft.EntityFrameworkCore.Migrations;
 7using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
 8
 9#nullable disable
 10
 11namespace Elsa.Persistence.EFCore.SqlServer.Migrations.Labels
 12{
 13    [DbContext(typeof(LabelsElsaDbContext))]
 14    [Migration("20260913133317_PerTenantLabelUniqueness")]
 15    partial class PerTenantLabelUniqueness
 16    {
 17        /// <inheritdoc />
 18        protected override void BuildTargetModel(ModelBuilder modelBuilder)
 19        {
 20#pragma warning disable 612, 618
 321            modelBuilder
 322                .HasDefaultSchema("Elsa")
 323                .HasAnnotation("ProductVersion", "9.0.17")
 324                .HasAnnotation("Relational:MaxIdentifierLength", 128);
 25
 326            SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
 27
 328            modelBuilder.Entity("Elsa.Labels.Entities.Label", b =>
 329                {
 330                    b.Property<string>("Id")
 331                        .HasColumnType("nvarchar(450)");
 332
 333                    b.Property<string>("Color")
 334                        .HasColumnType("nvarchar(max)");
 335
 336                    b.Property<string>("Description")
 337                        .HasColumnType("nvarchar(max)");
 338
 339                    b.Property<string>("Name")
 340                        .IsRequired()
 341                        .HasMaxLength(255)
 342                        .HasColumnType("nvarchar(255)");
 343
 344                    b.Property<string>("NormalizedName")
 345                        .IsRequired()
 346                        .HasMaxLength(255)
 347                        .HasColumnType("nvarchar(255)");
 348
 349                    b.Property<string>("TenantId")
 350                        .HasColumnType("nvarchar(450)");
 351
 352                    b.HasKey("Id");
 353
 354                    b.HasIndex("TenantId", "NormalizedName")
 355                        .IsUnique()
 356                        .HasDatabaseName("IX_Label_TenantId_NormalizedName")
 357                        .HasFilter("[TenantId] IS NOT NULL");
 358
 359                    b.ToTable("Labels", "Elsa");
 660                });
 61
 362            modelBuilder.Entity("Elsa.Labels.Entities.WorkflowDefinitionLabel", b =>
 363                {
 364                    b.Property<string>("Id")
 365                        .HasColumnType("nvarchar(450)");
 366
 367                    b.Property<string>("LabelId")
 368                        .IsRequired()
 369                        .HasColumnType("nvarchar(450)");
 370
 371                    b.Property<string>("TenantId")
 372                        .HasColumnType("nvarchar(450)");
 373
 374                    b.Property<string>("WorkflowDefinitionId")
 375                        .IsRequired()
 376                        .HasColumnType("nvarchar(450)");
 377
 378                    b.Property<string>("WorkflowDefinitionVersionId")
 379                        .IsRequired()
 380                        .HasColumnType("nvarchar(450)");
 381
 382                    b.HasKey("Id");
 383
 384                    b.HasIndex("LabelId")
 385                        .HasDatabaseName("WorkflowDefinitionLabel_LabelId");
 386
 387                    b.HasIndex("TenantId")
 388                        .HasDatabaseName("WorkflowDefinitionLabel_TenantId");
 389
 390                    b.HasIndex("WorkflowDefinitionId")
 391                        .HasDatabaseName("WorkflowDefinitionLabel_WorkflowDefinitionId");
 392
 393                    b.HasIndex("WorkflowDefinitionVersionId")
 394                        .HasDatabaseName("WorkflowDefinitionLabel_WorkflowDefinitionVersionId");
 395
 396                    b.ToTable("WorkflowDefinitionLabels", "Elsa");
 697                });
 98#pragma warning restore 612, 618
 399        }
 100    }
 101}