Skip to content

Commit 14e527e

Browse files
author
gauffininteractive
committed
Completed the database schema updater.
1 parent 7218772 commit 14e527e

File tree

17 files changed

+534
-123
lines changed

17 files changed

+534
-123
lines changed

src/Server/OneTrueError.Api.Client.Tests/TryTheClient.cs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ namespace OneTrueError.Api.Client.Tests
1313
#if DEBUG
1414
public class TryTheClient
1515
{
16-
[Fact]
16+
//[Fact]
1717
public async Task Test()
1818
{
19-
OneTrueClient client = new OneTrueClient();
20-
client.Credentials = new NetworkCredential("jonas", "123456");
21-
client.Open(new Uri("http://localhost/onetrueerror/"));
19+
OneTrueApiClient client = new OneTrueApiClient();
20+
client.Open(new Uri("http://localhost/onetrueerror/"), "o333", "kjsdklsdsdjkl");
2221
FindAccountByUserNameResult result = null;
2322
try
2423
{

src/Server/OneTrueError.Data.Common/IDatabaseUtilities.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,16 @@ namespace OneTrueError.Infrastructure
44
{
55
public interface ISetupDatabaseTools
66
{
7+
/// <summary>
8+
/// Check if the current DB schema is out of date compared to the embedded schema resources.
9+
/// </summary>
10+
bool CanSchemaBeUpgraded();
11+
12+
/// <summary>
13+
/// Update DB schema to latest version.
14+
/// </summary>
15+
void UpgradeDatabaseSchema();
16+
717
/// <summary>
818
/// Used to check if the given connection string actually works
919
/// </summary>

src/Server/OneTrueError.SqlServer.Tests/ConnectionFactory.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Configuration;
4+
using System.Data;
45
using System.Data.SqlClient;
56
using System.Linq;
67
using System.Text;
@@ -18,5 +19,13 @@ public static IAdoNetUnitOfWork Create()
1819
connection.Open();
1920
return new AdoNetUnitOfWork(connection, true);
2021
}
22+
23+
public static IDbConnection CreateConnection()
24+
{
25+
var connection = new SqlConnection();
26+
connection.ConnectionString = ConfigurationManager.ConnectionStrings["Db"].ConnectionString;
27+
connection.Open();
28+
return connection;
29+
}
2130
}
2231
}

src/Server/OneTrueError.SqlServer.Tests/OneTrueError.SqlServer.Tests.csproj

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@
8989
<Compile Include="Core\ApiKeys\Queries\ListApiKeysHandlerTests.cs" />
9090
<Compile Include="Modules\Geolocation\ErrorOriginRepositoryTests.cs" />
9191
<Compile Include="Properties\AssemblyInfo.cs" />
92+
<Compile Include="SchemaManagerTests.cs" />
93+
<Compile Include="TestTools.cs" />
9294
</ItemGroup>
9395
<ItemGroup>
9496
<None Include="app.config" />
@@ -103,6 +105,10 @@
103105
<Project>{5EF42A74-9323-49FA-A1F6-974D6DE77202}</Project>
104106
<Name>OneTrueError.App</Name>
105107
</ProjectReference>
108+
<ProjectReference Include="..\OneTrueError.Data.Common\OneTrueError.Infrastructure.csproj">
109+
<Project>{A78A50DA-C9D7-47F2-8528-D7EE39D91924}</Project>
110+
<Name>OneTrueError.Infrastructure</Name>
111+
</ProjectReference>
106112
<ProjectReference Include="..\OneTrueError.SqlServer\OneTrueError.SqlServer.csproj">
107113
<Project>{B967BEEA-CDDD-4A83-A4F2-1C946099ED51}</Project>
108114
<Name>OneTrueError.SqlServer</Name>
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
using System.Threading.Tasks;
6+
using FluentAssertions;
7+
using Griffin.Data.Mapper;
8+
using Xunit;
9+
10+
namespace OneTrueError.SqlServer.Tests
11+
{
12+
public class SchemaManagerTests
13+
{
14+
public const int LatestVersion = 3;
15+
16+
public SchemaManagerTests()
17+
{
18+
var sut = new SchemaManager(ConnectionFactory.CreateConnection);
19+
EnsureSchemaTable();
20+
}
21+
22+
[Fact]
23+
public void should_report_upgradable_if_schema_version_is_less()
24+
{
25+
SetVersion(1);
26+
27+
var sut = new SchemaManager(ConnectionFactory.CreateConnection);
28+
var actual = sut.CanSchemaBeUpgraded();
29+
30+
actual.Should().BeTrue();
31+
}
32+
33+
[Fact]
34+
public void should_not_report_upgradable_if_schema_version_is_same()
35+
{
36+
SetVersion(3);
37+
38+
var sut = new SchemaManager(ConnectionFactory.CreateConnection);
39+
var actual = sut.CanSchemaBeUpgraded();
40+
41+
actual.Should().BeFalse();
42+
}
43+
44+
[Fact]
45+
public void should_report_upgradable_if_schema_table_is_missing()
46+
{
47+
DropSchemaTable();
48+
49+
var sut = new SchemaManager(ConnectionFactory.CreateConnection);
50+
var actual = sut.CanSchemaBeUpgraded();
51+
52+
actual.Should().BeTrue();
53+
}
54+
55+
[Fact]
56+
public void should_be_able_to_upgrade_schema()
57+
{
58+
59+
var sut = new SchemaManager(ConnectionFactory.CreateConnection);
60+
sut.UpgradeDatabaseSchema();
61+
62+
63+
}
64+
65+
66+
[Fact]
67+
public void should_be_able_to_upgrade_database()
68+
{
69+
using (var tools = new TestTools())
70+
{
71+
tools.CreateDatabase();
72+
73+
var sut = new SchemaManager(tools.CreateConnection);
74+
sut.UpgradeDatabaseSchema();
75+
}
76+
}
77+
78+
79+
private void SetVersion(int version)
80+
{
81+
using (var con = SqlServerTools.OpenConnection())
82+
{
83+
con.ExecuteNonQuery("UPDATE DatabaseSchema SET Version = @version", new {version = version});
84+
}
85+
}
86+
87+
private void EnsureSchemaTable()
88+
{
89+
using (var con = SqlServerTools.OpenConnection())
90+
{
91+
con.ExecuteNonQuery(@"
92+
IF OBJECT_ID(N'dbo.[DatabaseSchema]', N'U') IS NULL
93+
BEGIN
94+
CREATE TABLE [dbo].[DatabaseSchema] (
95+
[Version] int not null default 1
96+
);
97+
INSERT INTO DatabaseSchema VALUES(1);
98+
END
99+
");
100+
}
101+
}
102+
103+
private void DropSchemaTable()
104+
{
105+
using (var con = SqlServerTools.OpenConnection())
106+
{
107+
con.ExecuteNonQuery(@"DROP TABLE [dbo].[DatabaseSchema]");
108+
}
109+
}
110+
}
111+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Data;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using Griffin.Data.Mapper;
8+
using OneTrueError.Infrastructure;
9+
10+
namespace OneTrueError.SqlServer.Tests
11+
{
12+
public class TestTools : IDisposable
13+
{
14+
private string _dbName;
15+
16+
public void CreateDatabase()
17+
{
18+
using (var con = ConnectionFactory.CreateConnection())
19+
{
20+
_dbName = "T" + Guid.NewGuid().ToString("N");
21+
con.ExecuteNonQuery("CREATE Database " + _dbName);
22+
con.ChangeDatabase(_dbName);
23+
var schemaTool = new SchemaManager(() => con);
24+
schemaTool.CreateInitialStructure();
25+
}
26+
}
27+
28+
public IDbConnection CreateConnection()
29+
{
30+
var connection = ConnectionFactory.CreateConnection();
31+
connection.ChangeDatabase(_dbName);
32+
return connection;
33+
}
34+
35+
public void Dispose()
36+
{
37+
if (_dbName == null)
38+
return;
39+
40+
using (var con = ConnectionFactory.CreateConnection())
41+
{
42+
var sql =
43+
string.Format("alter database {0} set single_user with rollback immediate; DROP Database {0}",
44+
_dbName);
45+
con.ExecuteNonQuery(sql);
46+
}
47+
}
48+
}
49+
}

src/Server/OneTrueError.SqlServer/OneTrueError.SqlServer.csproj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
<Compile Include="Core\ApiKeys\Queries\ListApiKeysHandler.cs" />
8181
<Compile Include="Core\ApiKeys\Mappings\MirrorMapper.cs" />
8282
<Compile Include="DbConverters.cs" />
83+
<Compile Include="SchemaManager.cs" />
8384
<Compile Include="Web\Feedback\Queries\GetOverviewFeedbackHandler.cs" />
8485
<Compile Include="Web\Feedback\Queries\GetOverviewFeedbackResultItemMapper.cs" />
8586
<Compile Include="Core\Incidents\ReportDayMapper.cs" />
@@ -169,11 +170,17 @@
169170
</ProjectReference>
170171
</ItemGroup>
171172
<ItemGroup>
172-
<EmbeddedResource Include="Database.sql" />
173+
<EmbeddedResource Include="Schema\Database.sql" />
173174
</ItemGroup>
174175
<ItemGroup>
175176
<Folder Include="Core\Accounts\CommandHandlers\" />
176177
</ItemGroup>
178+
<ItemGroup>
179+
<EmbeddedResource Include="Schema\Update.v2.sql" />
180+
</ItemGroup>
181+
<ItemGroup>
182+
<EmbeddedResource Include="Schema\Update.v3.sql" />
183+
</ItemGroup>
177184
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
178185
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
179186
Other similar extension points exist, see Microsoft.Common.targets.

src/Server/OneTrueError.SqlServer/Database.sql renamed to src/Server/OneTrueError.SqlServer/Schema/Database.sql

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -323,80 +323,3 @@ BEGIN
323323

324324
);
325325
END
326-
327-
IF OBJECT_ID(N'dbo.[DatabaseSchema]', N'U') IS NULL
328-
BEGIN
329-
CREATE TABLE [dbo].[DatabaseSchema] (
330-
[Version] int not null default 1
331-
);
332-
END
333-
334-
DECLARE @schemaVersion int;
335-
SELECT @schemaVersion = Version FROM DatabaseSchema;
336-
337-
IF OBJECT_ID(N'dbo.[ApiKeys]', N'U') IS NULL
338-
BEGIN
339-
CREATE TABLE [dbo].[ApiKeys] (
340-
[Id] INT identity not NULL primary key,
341-
[ApplicationName] varchar(40) NOT NULL,
342-
[CreatedAtUtc] DATETIME NOT NULL,
343-
[CreatedById] int NOT NULL,
344-
[GeneratedKey] varchar(36) NOT NULL,
345-
[SharedSecret] varchar(36) NOT NULL
346-
);
347-
CREATE TABLE [dbo].[ApiKeyApplications] (
348-
[ApiKeyId] INT not NULL,
349-
[ApplicationId] INT NOT NULL,
350-
Primary key (ApiKeyId, ApplicationId),
351-
FOREIGN KEY (ApiKeyId) REFERENCES ApiKeys(Id) ON DELETE CASCADE,
352-
FOREIGN KEY (ApplicationId) REFERENCES Applications(Id) ON DELETE NO ACTION
353-
);
354-
update DatabaseSchema SET Version = 2;
355-
END
356-
357-
IF @schemaVersion < 3
358-
BEGIN
359-
ALTER TABLE Incidents ADD PRIMARY KEY (Id);
360-
ALTER TABLE ErrorReportOrigins WITH CHECK ADD CONSTRAINT FK_ErrorReportOrigins_Reports FOREIGN KEY (ReportId) REFERENCES ErrorReports (Id) ON DELETE CASCADE;
361-
ALTER TABLE ErrorReports WITH CHECK ADD CONSTRAINT FK_ErrorReports_Incidents FOREIGN KEY (IncidentId) REFERENCES Incidents (Id) ON DELETE CASCADE;
362-
ALTER TABLE CollectionMetadata WITH CHECK ADD CONSTRAINT FK_COLME_applicationId FOREIGN KEY (ApplicationId) REFERENCES Applications (Id) ON DELETE CASCADE;
363-
ALTER TABLE IncidentFeedback WITH CHECK ADD CONSTRAINT FK_IncidentFeedback_incidents FOREIGN KEY (IncidentId) REFERENCES Incidents (Id) ON DELETE CASCADE;
364-
ALTER TABLE Incidents WITH CHECK ADD CONSTRAINT FK_Incidents_applicationId FOREIGN KEY (ApplicationId) REFERENCES Applications (Id) ON DELETE CASCADE;
365-
ALTER TABLE IncidentTags WITH CHECK ADD CONSTRAINT FK_IncidentTags_incidentId FOREIGN KEY (IncidentId) REFERENCES Incidents (Id) ON DELETE CASCADE;
366-
ALTER TABLE ReportContextInfo WITH CHECK ADD CONSTRAINT FK_ReportContextInfo_incidentId FOREIGN KEY (IncidentId) REFERENCES Incidents (Id) ON DELETE CASCADE;
367-
ALTER TABLE IncidentContextCollections WITH CHECK ADD CONSTRAINT FK_ICC_incidentId FOREIGN KEY (IncidentId) REFERENCES Incidents (Id) ON DELETE CASCADE;
368-
ALTER TABLE [UserNotificationSettings] WITH CHECK ADD CONSTRAINT FK_UNS_accounts FOREIGN KEY (AccountId) REFERENCES Accounts (Id) ON DELETE CASCADE;
369-
ALTER TABLE [Triggers] WITH CHECK ADD CONSTRAINT FK_Triggers_applicationId FOREIGN KEY (ApplicationId) REFERENCES Applications (Id) ON DELETE CASCADE;
370-
371-
DECLARE @ConstraintName nvarchar(200)
372-
SELECT @ConstraintName = KCU.CONSTRAINT_NAME
373-
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
374-
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
375-
ON KCU.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
376-
AND KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
377-
AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
378-
WHERE
379-
KCU.TABLE_NAME = 'ApplicationMembers' AND
380-
KCU.COLUMN_NAME = 'AccountId'
381-
IF @ConstraintName IS NOT NULL
382-
BEGIN
383-
EXEC('ALTER TABLE ApplicationMembers DROP CONSTRAINT ' + @ConstraintName)
384-
END;
385-
SELECT @ConstraintName = KCU.CONSTRAINT_NAME
386-
FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
387-
INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU
388-
ON KCU.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
389-
AND KCU.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
390-
AND KCU.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
391-
WHERE
392-
KCU.TABLE_NAME = 'ApplicationMembers' AND
393-
KCU.COLUMN_NAME = 'ApplicationId'
394-
IF @ConstraintName IS NOT NULL
395-
BEGIN
396-
EXEC('ALTER TABLE ApplicationMembers DROP CONSTRAINT ' + @ConstraintName)
397-
END
398-
ALTER TABLE ApplicationMembers WITH CHECK ADD CONSTRAINT FK_AppMemb_Accounts FOREIGN KEY (AccountId) REFERENCES Accounts (Id) ON DELETE CASCADE;
399-
ALTER TABLE ApplicationMembers WITH CHECK ADD CONSTRAINT FK_AppMemb_Applications FOREIGN KEY (ApplicationId) REFERENCES Applications (Id) ON DELETE CASCADE;
400-
401-
UPDATE DatabaseSchema SET Version = 3;
402-
END
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
IF OBJECT_ID(N'dbo.[DatabaseSchema]', N'U') IS NULL
2+
BEGIN
3+
CREATE TABLE [dbo].[DatabaseSchema] (
4+
[Version] int not null default 1
5+
);
6+
INSERT INTO DatabaseSchema VALUES(1);
7+
END
8+
9+
IF OBJECT_ID(N'dbo.[ApiKeys]', N'U') IS NULL
10+
BEGIN
11+
CREATE TABLE [dbo].[ApiKeys] (
12+
[Id] INT identity not NULL primary key,
13+
[ApplicationName] varchar(40) NOT NULL,
14+
[CreatedAtUtc] DATETIME NOT NULL,
15+
[CreatedById] int NOT NULL,
16+
[GeneratedKey] varchar(36) NOT NULL,
17+
[SharedSecret] varchar(36) NOT NULL
18+
);
19+
CREATE TABLE [dbo].[ApiKeyApplications] (
20+
[ApiKeyId] INT not NULL,
21+
[ApplicationId] INT NOT NULL,
22+
Primary key (ApiKeyId, ApplicationId),
23+
FOREIGN KEY (ApiKeyId) REFERENCES ApiKeys(Id) ON DELETE CASCADE,
24+
FOREIGN KEY (ApplicationId) REFERENCES Applications(Id) ON DELETE NO ACTION
25+
);
26+
update DatabaseSchema SET Version = 2;
27+
END

0 commit comments

Comments
 (0)