Skip to content

Commit c240ce5

Browse files
committed
Redo enum label addition (#3425)
To better handling reordering scenarios. Fixes #3424 (cherry picked from commit c2b3de4)
1 parent e5e901e commit c240ce5

File tree

2 files changed

+53
-7
lines changed

2 files changed

+53
-7
lines changed

src/EFCore.PG/Migrations/NpgsqlMigrationsSqlGenerator.cs

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1266,18 +1266,34 @@ protected virtual void GenerateEnumStatements(AlterDatabaseOperation operation,
12661266
+ "https://www.postgresql.org/docs/current/sql-altertype.html)");
12671267
}
12681268

1269-
for (var (newPos, oldPos) = (0, 0); newPos < newLabels.Count; newPos++)
1269+
for (var newPos = 0; newPos < newLabels.Count; newPos++)
12701270
{
12711271
var newLabel = newLabels[newPos];
1272-
var oldLabel = oldPos < oldLabels.Count ? oldLabels[oldPos] : null;
1273-
1274-
if (newLabel == oldLabel)
1272+
if (oldLabels.Contains(newLabel))
12751273
{
1276-
oldPos++;
12771274
continue;
12781275
}
12791276

1280-
GenerateAddEnumLabel(newEnum, newLabel, oldLabel, model, builder);
1277+
// We add the new label just after the last one we have in the new labels definition (when the last one is new, it will have
1278+
// just been added).
1279+
// If the new label happens to be the first one, add it before the first old label. Otherwise, if there are no old labels,
1280+
// just append the label (no before/after).
1281+
if (newPos == newLabels.Count - 1)
1282+
{
1283+
GenerateAddEnumLabel(newEnum, newLabel, beforeLabel: null, afterLabel: null, model, builder);
1284+
}
1285+
else if (newPos > 0)
1286+
{
1287+
GenerateAddEnumLabel(newEnum, newLabel, beforeLabel: null, afterLabel: newLabels[newPos - 1], model, builder);
1288+
}
1289+
else if (oldLabels.Count > 0)
1290+
{
1291+
GenerateAddEnumLabel(newEnum, newLabel, beforeLabel: oldLabels[0], afterLabel: null, model, builder);
1292+
}
1293+
else
1294+
{
1295+
GenerateAddEnumLabel(newEnum, newLabel, beforeLabel: null, afterLabel: null, model, builder);
1296+
}
12811297
}
12821298
}
12831299
}
@@ -1328,9 +1344,15 @@ protected virtual void GenerateAddEnumLabel(
13281344
PostgresEnum enumType,
13291345
string addedLabel,
13301346
string? beforeLabel,
1347+
string? afterLabel,
13311348
IModel? model,
13321349
MigrationCommandListBuilder builder)
13331350
{
1351+
if (beforeLabel is not null && afterLabel is not null)
1352+
{
1353+
throw new UnreachableException("Both beforeLabel and afterLabel can't be specified");
1354+
}
1355+
13341356
var schema = enumType.Schema ?? model?.GetDefaultSchema();
13351357

13361358
builder
@@ -1345,6 +1367,12 @@ protected virtual void GenerateAddEnumLabel(
13451367
.Append(" BEFORE ")
13461368
.Append(_stringTypeMapping.GenerateSqlLiteral(beforeLabel));
13471369
}
1370+
else if (afterLabel is not null)
1371+
{
1372+
builder
1373+
.Append(" AFTER ")
1374+
.Append(_stringTypeMapping.GenerateSqlLiteral(afterLabel));
1375+
}
13481376

13491377
builder.AppendLine(";");
13501378

test/EFCore.PG.FunctionalTests/Migrations/MigrationsNpgsqlTest.cs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2895,7 +2895,25 @@ await Test(
28952895
l => Assert.Equal("Sad", l));
28962896
});
28972897

2898-
AssertSql("""ALTER TYPE "Mood" ADD VALUE 'Angry' BEFORE 'Sad';""");
2898+
AssertSql("""ALTER TYPE "Mood" ADD VALUE 'Angry' AFTER 'Happy';""");
2899+
}
2900+
2901+
[Fact]
2902+
public virtual async Task Alter_enum_change_label_ordering_does_nothing()
2903+
{
2904+
await Test(
2905+
builder => builder.HasPostgresEnum("Mood", ["Happy", "Sad"]),
2906+
builder => builder.HasPostgresEnum("Mood", ["Sad", "Happy"]),
2907+
model =>
2908+
{
2909+
var moodEnum = Assert.Single(model.GetPostgresEnums());
2910+
Assert.Collection(
2911+
moodEnum.Labels,
2912+
l => Assert.Equal("Happy", l),
2913+
l => Assert.Equal("Sad", l));
2914+
});
2915+
2916+
AssertSql();
28992917
}
29002918

29012919
[Fact]

0 commit comments

Comments
 (0)