Skip to content

Commit

Permalink
Fix migration history table lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Jun 5, 2023
1 parent 6cadc0b commit 9b088f5
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 18 deletions.
27 changes: 9 additions & 18 deletions src/EFCore.PG/Migrations/Internal/NpgsqlHistoryRepository.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,26 +31,17 @@ protected override string ExistsSql
{
get
{
var builder = new StringBuilder();

builder.Append("SELECT EXISTS (SELECT 1 FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace WHERE ");

var stringTypeMapping = Dependencies.TypeMappingSource.GetMapping(typeof(string));

if (TableSchema is not null)
{
builder
.Append("n.nspname=")
.Append(stringTypeMapping.GenerateSqlLiteral(TableSchema))
.Append(" AND ");
}

builder
.Append("c.relname=")
.Append(stringTypeMapping.GenerateSqlLiteral(TableName))
.Append(");");

return builder.ToString();
return
$"""
SELECT EXISTS (
SELECT 1 FROM pg_catalog.pg_class c
JOIN pg_catalog.pg_namespace n ON n.oid=c.relnamespace
WHERE n.nspname={stringTypeMapping.GenerateSqlLiteral(TableSchema ?? "public")} AND
c.relname={stringTypeMapping.GenerateSqlLiteral(TableName)}
)
""";
}
}

Expand Down
189 changes: 189 additions & 0 deletions test/EFCore.PG.Tests/Migrations/NpgsqlHistoryRepositoryTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
using Npgsql.EntityFrameworkCore.PostgreSQL.TestUtilities;

namespace Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;

public class NpgsqlHistoryRepositoryTest
{
[ConditionalFact]
public void GetCreateScript_works()
{
var sql = CreateHistoryRepository().GetCreateScript();

Assert.Equal(
"""
CREATE TABLE "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetCreateScript_works_with_schema()
{
var sql = CreateHistoryRepository("my").GetCreateScript();

Assert.Equal(
"""
DO $EF$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'my') THEN
CREATE SCHEMA my;
END IF;
END $EF$;
CREATE TABLE my."__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetCreateIfNotExistsScript_works()
{
var sql = CreateHistoryRepository().GetCreateIfNotExistsScript();

Assert.Equal(
"""
CREATE TABLE IF NOT EXISTS "__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetCreateIfNotExistsScript_works_with_schema()
{
var sql = CreateHistoryRepository("my").GetCreateIfNotExistsScript();

Assert.Equal(
"""
DO $EF$
BEGIN
IF NOT EXISTS(SELECT 1 FROM pg_namespace WHERE nspname = 'my') THEN
CREATE SCHEMA my;
END IF;
END $EF$;
CREATE TABLE IF NOT EXISTS my."__EFMigrationsHistory" (
"MigrationId" character varying(150) NOT NULL,
"ProductVersion" character varying(32) NOT NULL,
CONSTRAINT "PK___EFMigrationsHistory" PRIMARY KEY ("MigrationId")
);
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetDeleteScript_works()
{
var sql = CreateHistoryRepository().GetDeleteScript("Migration1");

Assert.Equal(
"""
DELETE FROM "__EFMigrationsHistory"
WHERE "MigrationId" = 'Migration1';
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetInsertScript_works()
{
var sql = CreateHistoryRepository().GetInsertScript(
new HistoryRow("Migration1", "7.0.0"));

Assert.Equal(
"""
INSERT INTO "__EFMigrationsHistory" ("MigrationId", "ProductVersion")
VALUES ('Migration1', '7.0.0');
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetBeginIfNotExistsScript_works()
{
var sql = CreateHistoryRepository().GetBeginIfNotExistsScript("Migration1");

Assert.Equal(
"""
DO $EF$
BEGIN
IF NOT EXISTS(SELECT 1 FROM "__EFMigrationsHistory" WHERE "MigrationId" = 'Migration1') THEN
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetBeginIfExistsScript_works()
{
var sql = CreateHistoryRepository().GetBeginIfExistsScript("Migration1");

Assert.Equal(
"""
DO $EF$
BEGIN
IF EXISTS(SELECT 1 FROM "__EFMigrationsHistory" WHERE "MigrationId" = 'Migration1') THEN
""", sql, ignoreLineEndingDifferences: true);
}

[ConditionalFact]
public void GetEndIfScript_works()
{
var sql = CreateHistoryRepository().GetEndIfScript();

Assert.Equal(
"""
END IF;
END $EF$;
""", sql, ignoreLineEndingDifferences: true);
}

private static IHistoryRepository CreateHistoryRepository(string schema = null)
=> new TestDbContext(
new DbContextOptionsBuilder()
.UseInternalServiceProvider(NpgsqlTestHelpers.Instance.CreateServiceProvider())
.UseNpgsql(
new NpgsqlConnection("Host=localhost;Database=DummyDatabase"),
b => b.MigrationsHistoryTable(HistoryRepository.DefaultTableName, schema))
.Options)
.GetService<IHistoryRepository>();

private class TestDbContext : DbContext
{
public TestDbContext(DbContextOptions options)
: base(options)
{
}

public DbSet<Blog> Blogs { get; set; }

[DbFunction("TableFunction")]
public IQueryable<TableFunction> TableFunction()
=> FromExpression(() => TableFunction());

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
}
}

private class Blog
{
public int Id { get; set; }
}

private class TableFunction
{
public int Id { get; set; }
public int BlogId { get; set; }
public Blog Blog { get; set; }
}
}

0 comments on commit 9b088f5

Please sign in to comment.