Skip to content

Commit 492c62a

Browse files
authored
Fix EnsureSchema method replacement (#5)
* Refactor and Add Tests * Add schema to EnsureSchema method #4 * update Package Version --------- Co-authored-by: Jérémie DEVILLARD <jdevillard@users.noreply.github.com>
1 parent b3f1eaf commit 492c62a

6 files changed

Lines changed: 257 additions & 11 deletions

File tree

EFMigrationRuntimeSchema.sln

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ef-migration-runtime-schema
99
EndProject
1010
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution", "solution", "{AA4788FF-0A90-4BD1-B33E-D95FB0DC927F}"
1111
ProjectSection(SolutionItems) = preProject
12+
LICENSE = LICENSE
1213
README.md = README.md
1314
EndProjectSection
1415
EndProject
16+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ef-migration-runtimeschema.Tests", "ef-migration-runtimeschema.Tests\ef-migration-runtimeschema.Tests.csproj", "{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C}"
17+
EndProject
1518
Global
1619
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1720
Debug|Any CPU = Debug|Any CPU
@@ -22,12 +25,17 @@ Global
2225
{C53FC521-41AD-4ACE-8D4A-3566AADC75CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
2326
{C53FC521-41AD-4ACE-8D4A-3566AADC75CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
2427
{C53FC521-41AD-4ACE-8D4A-3566AADC75CC}.Release|Any CPU.Build.0 = Release|Any CPU
28+
{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29+
{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C}.Debug|Any CPU.Build.0 = Debug|Any CPU
30+
{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C}.Release|Any CPU.ActiveCfg = Release|Any CPU
31+
{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C}.Release|Any CPU.Build.0 = Release|Any CPU
2532
EndGlobalSection
2633
GlobalSection(SolutionProperties) = preSolution
2734
HideSolutionNode = FALSE
2835
EndGlobalSection
2936
GlobalSection(NestedProjects) = preSolution
3037
{C53FC521-41AD-4ACE-8D4A-3566AADC75CC} = {AD4135C5-9840-4384-9637-BCDF50D5757E}
38+
{5F6954D5-0BE6-4DF4-9C0E-80A35A06A16C} = {AD4135C5-9840-4384-9637-BCDF50D5757E}
3139
EndGlobalSection
3240
GlobalSection(ExtensibilityGlobals) = postSolution
3341
SolutionGuid = {D4A97E1A-9797-4B04-A831-EF4B383BD138}
Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
using JDEV.EFMigrationRuntimeSchema;
2+
3+
namespace ef_migration_runtimeschema.Tests
4+
{
5+
public class RewriteTest
6+
{
7+
8+
const string completeClassString = @"
9+
public partial class AddUserName : Migration
10+
11+
12+
/// <inheritdoc />
13+
protected override void Up(MigrationBuilder migrationBuilder)
14+
{
15+
migrationBuilder.AddColumn<string>(
16+
name: ""FullName"",
17+
schema:""schema"",
18+
table: ""Customers"",
19+
nullable: true);
20+
}
21+
}
22+
";
23+
const string interfaceName = "InterfaceName";
24+
25+
[Fact]
26+
public void ShouldAddConstructor()
27+
{
28+
var constructorClassString = @"
29+
public partial class AddUserName : Migration
30+
{
31+
}
32+
";
33+
34+
var final = @"
35+
public partial class AddUserName : Migration
36+
{
37+
private readonly InterfaceName _schema;
38+
39+
/// <inheritdoc />
40+
public AddUserName(InterfaceName schema)
41+
{
42+
_schema = schema;
43+
}
44+
}
45+
";
46+
47+
var result = MigrationCommand.RewriteSyntaxtNode(interfaceName,"testPath", constructorClassString);
48+
var str = result.ToFullString();
49+
50+
Assert.Equal(final, str,ignoreLineEndingDifferences:true);
51+
}
52+
53+
[Fact]
54+
public void ShouldNotAddTwoConstructors()
55+
{
56+
var constructorClassString = @"
57+
public partial class AddUserName : Migration
58+
{
59+
private readonly InterfaceName _schema;
60+
61+
/// <inheritdoc />
62+
public AddUserName(InterfaceName schema)
63+
{
64+
_schema = schema;
65+
}
66+
}
67+
";
68+
69+
var final = @"
70+
public partial class AddUserName : Migration
71+
{
72+
private readonly InterfaceName _schema;
73+
74+
/// <inheritdoc />
75+
public AddUserName(InterfaceName schema)
76+
{
77+
_schema = schema;
78+
}
79+
}
80+
";
81+
82+
var result = MigrationCommand.RewriteSyntaxtNode(interfaceName, "testPath", constructorClassString);
83+
var str = result.ToFullString();
84+
85+
Assert.Equal(final, str, ignoreLineEndingDifferences: true, ignoreWhiteSpaceDifferences:true);
86+
}
87+
88+
89+
[Fact]
90+
public void ShouldReplaceSchemaNameInAddColumn()
91+
{
92+
var classString = @"
93+
public partial class AddUserName : Migration
94+
{
95+
96+
/// <inheritdoc />
97+
protected override void Up(MigrationBuilder migrationBuilder)
98+
{
99+
migrationBuilder.AddColumn<string>(
100+
name: ""FullName"",
101+
schema:""schema"",
102+
table: ""Customers"",
103+
nullable: true);
104+
}
105+
}
106+
";
107+
108+
var final = @"
109+
public partial class AddUserName : Migration
110+
{
111+
private readonly InterfaceName _schema;
112+
113+
/// <inheritdoc />
114+
public AddUserName(InterfaceName schema)
115+
{
116+
_schema = schema;
117+
}
118+
119+
/// <inheritdoc />
120+
protected override void Up(MigrationBuilder migrationBuilder)
121+
{
122+
migrationBuilder.AddColumn<string>(
123+
name: ""FullName"",
124+
schema:_schema.Schema,
125+
table: ""Customers"",
126+
nullable: true);
127+
}
128+
}
129+
";
130+
131+
var result = MigrationCommand.RewriteSyntaxtNode(interfaceName, "testPath", classString);
132+
var str = result.ToFullString();
133+
134+
Assert.Equal(final, str, ignoreLineEndingDifferences: true);
135+
}
136+
137+
138+
139+
[Fact]
140+
public void ShouldReplaceSchemaInMethodEnsureSchema()
141+
{
142+
var classString = @"
143+
public partial class AddUserName : Migration
144+
{
145+
146+
/// <inheritdoc />
147+
protected override void Up(MigrationBuilder migrationBuilder)
148+
{
149+
migrationBuilder.EnsureSchema(
150+
name: ""schema"");
151+
}
152+
}
153+
";
154+
155+
var final = @"
156+
public partial class AddUserName : Migration
157+
{
158+
private readonly InterfaceName _schema;
159+
160+
/// <inheritdoc />
161+
public AddUserName(InterfaceName schema)
162+
{
163+
_schema = schema;
164+
}
165+
166+
/// <inheritdoc />
167+
protected override void Up(MigrationBuilder migrationBuilder)
168+
{
169+
migrationBuilder.EnsureSchema(
170+
name: _schema.Schema);
171+
}
172+
}
173+
";
174+
175+
var result = MigrationCommand.RewriteSyntaxtNode(interfaceName, "testPath", classString);
176+
var str = result.ToFullString();
177+
178+
Assert.Equal(final, str, ignoreLineEndingDifferences: true);
179+
}
180+
181+
}
182+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<RootNamespace>ef_migration_runtimeschema.Tests</RootNamespace>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
9+
<IsPackable>false</IsPackable>
10+
<IsTestProject>true</IsTestProject>
11+
</PropertyGroup>
12+
13+
<ItemGroup>
14+
<PackageReference Include="coverlet.collector" Version="6.0.0" />
15+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.8.0" />
16+
<PackageReference Include="xunit" Version="2.5.3" />
17+
<PackageReference Include="xunit.runner.visualstudio" Version="2.5.3" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<ProjectReference Include="..\src\ef-migration-runtimeschema\ef-migration-runtime-schema.csproj" />
22+
</ItemGroup>
23+
24+
<ItemGroup>
25+
<Using Include="Xunit" />
26+
</ItemGroup>
27+
28+
</Project>

src/ef-migration-runtimeschema/MigrationCommand.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,16 @@ public void Execute(string interfaceName, string migrationFilePath)
1414
// creation of the syntax tree for every file
1515
var programPath = migrationFilePath;
1616
var programText = File.ReadAllText(programPath);
17+
SyntaxNode result = RewriteSyntaxtNode(interfaceName, programPath, programText);
18+
19+
using var fileWriter = new StreamWriter(programPath, append: false);
20+
result.WriteTo(fileWriter);
21+
}
22+
23+
public static SyntaxNode RewriteSyntaxtNode(string interfaceName, string programPath, string programText)
24+
{
1725
SyntaxTree programTree = CSharpSyntaxTree.ParseText(programText)
18-
.WithFilePath(programPath);
26+
.WithFilePath(programPath);
1927

2028
var root = (CompilationUnitSyntax)programTree.GetRoot();
2129

@@ -30,7 +38,7 @@ public void Execute(string interfaceName, string migrationFilePath)
3038
SyntaxFactory.Parameter(SyntaxFactory.Identifier("schema"))
3139
.WithType(SyntaxFactory.ParseTypeName(schemaInterface)))
3240
.WithBody(SyntaxFactory.Block(SyntaxFactory.ParseStatement($"_schema = schema;"))
33-
41+
3442
);
3543

3644
var field = SyntaxFactory.FieldDeclaration(
@@ -70,9 +78,7 @@ public void Execute(string interfaceName, string migrationFilePath)
7078

7179
var schemaRewriter = new SchemaRewriter();
7280
var result = schemaRewriter.Visit(formattedRoot);
73-
74-
using var fileWriter = new StreamWriter(programPath, append: false);
75-
result.WriteTo(fileWriter);
81+
return result;
7682
}
7783
}
7884
}
Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,43 @@
11
using Microsoft.CodeAnalysis;
22
using Microsoft.CodeAnalysis.CSharp;
33
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
using System.Linq.Expressions;
45

56
namespace JDEV.EFMigrationRuntimeSchema
67
{
78
public class SchemaRewriter : CSharpSyntaxRewriter
89
{
910
public override SyntaxNode? VisitArgument(ArgumentSyntax node)
1011
{
12+
//Replace Schema for Up and Down
1113
if (node.NameColon?.Name.Identifier.Text == "schema")
12-
return SyntaxFactory.Argument(
13-
SyntaxFactory.MemberAccessExpression(
14-
SyntaxKind.SimpleMemberAccessExpression,
15-
SyntaxFactory.IdentifierName("_schema"),
16-
SyntaxFactory.IdentifierName("Schema")))
17-
.WithNameColon(node.NameColon);
14+
return CreateSchemaRefnode(node);
1815

16+
17+
//Replace Schema Name for migrationBuilder.EnsureSchema()
18+
if (node.NameColon?.Name.Identifier.Text == "name"
19+
&& node.Parent != null
20+
&& node.Parent.Parent.IsKind(SyntaxKind.InvocationExpression))
21+
{
22+
var methodNode = node.Parent.Parent.DescendantNodesAndSelf().OfType<InvocationExpressionSyntax>().First();
23+
var nameMethod = (methodNode.Expression as MemberAccessExpressionSyntax)?.Name;
24+
25+
if(nameMethod?.Identifier.Text =="EnsureSchema")
26+
return CreateSchemaRefnode(node);
27+
}
28+
1929
return base.VisitArgument(node);
2030
}
31+
32+
private static SyntaxNode CreateSchemaRefnode(ArgumentSyntax node)
33+
{
34+
return SyntaxFactory.Argument(
35+
SyntaxFactory.MemberAccessExpression(
36+
SyntaxKind.SimpleMemberAccessExpression,
37+
SyntaxFactory.IdentifierName("_schema"),
38+
SyntaxFactory.IdentifierName("Schema")))
39+
.WithNameColon(node.NameColon);
40+
}
41+
2142
}
2243
}

src/ef-migration-runtimeschema/ef-migration-runtime-schema.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<PackageTags>efcore cli</PackageTags>
2323
<PackageProjectUrl>https://github.com/jdevillard/ef-migration-runtime-schema</PackageProjectUrl>
2424
<RepositoryUrl>https://github.com/jdevillard/ef-migration-runtime-schema</RepositoryUrl>
25+
<PackageVersion>1.0.1</PackageVersion>
2526
</PropertyGroup>
2627

2728
<ItemGroup>

0 commit comments

Comments
 (0)