Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add the ability to use schema names for tables in table names #572

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 21 additions & 9 deletions src/MiniProfiler.Providers.MySql/MySqlStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Dapper;
using MySqlConnector;
Expand Down Expand Up @@ -227,14 +228,14 @@ public override async Task<MiniProfiler> LoadAsync(Guid id)
}

/// <summary>
/// Sets a particular profiler session so it is considered "unviewed"
/// Sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
public override void SetUnviewed(string user, Guid id) => ToggleViewed(user, id, false);

/// <summary>
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
Expand Down Expand Up @@ -370,10 +371,21 @@ SELECT Id
}

/// <summary>
/// Returns a connection to MySQL Server.
/// Returns a connection to MySQL.
/// </summary>
protected override DbConnection GetConnection() => new MySqlConnection(ConnectionString);

/// <summary>
/// SQL statements to create the MySQL schema names.
/// </summary>
protected override IEnumerable<string> GetSchemaNameCreationScripts(IEnumerable<string> schemaNames)
{
foreach (var schemaName in schemaNames)
{
yield return $@"CREATE SCHEMA IF NOT EXISTS [{schemaName}]";
}
}

/// <summary>
/// SQL statements to create the MySQL tables.
/// </summary>
Expand All @@ -393,8 +405,8 @@ User varchar(100) null,
MachineName varchar(100) null,
CustomLinksJson longtext,
ClientTimingsRedirectCount int null,
UNIQUE INDEX IX_{MiniProfilersTable}_Id (Id), -- displaying results selects everything based on the main MiniProfilers.Id column
INDEX IX_{MiniProfilersTable}_User_HasUserViewed (User, HasUserViewed) -- speeds up a query that is called on every .Stop()
UNIQUE INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id (Id), -- displaying results selects everything based on the main MiniProfilers.Id column
INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_User_HasUserViewed (User, HasUserViewed) -- speeds up a query that is called on every .Stop()
) engine=InnoDB collate utf8mb4_bin;";
yield return $@"
CREATE TABLE {MiniProfilerTimingsTable}
Expand All @@ -409,8 +421,8 @@ StartMilliseconds decimal(15,3) not null,
IsRoot bool not null,
Depth smallint not null,
CustomTimingsJson longtext null,
UNIQUE INDEX IX_{MiniProfilerTimingsTable}_Id (Id),
INDEX IX_{MiniProfilerTimingsTable}_MiniProfilerId (MiniProfilerId)
UNIQUE INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id (Id),
INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId (MiniProfilerId)
) engine=InnoDB collate utf8mb4_bin;";
yield return $@"
CREATE TABLE {MiniProfilerClientTimingsTable}
Expand All @@ -421,8 +433,8 @@ MiniProfilerId char(36) not null collate ascii_general_ci,
Name varchar(200) not null,
Start decimal(9, 3) not null,
Duration decimal(9, 3) not null,
UNIQUE INDEX IX_{MiniProfilerClientTimingsTable}_Id (Id),
INDEX IX_{MiniProfilerClientTimingsTable}_MiniProfilerId (MiniProfilerId)
UNIQUE INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id (Id),
INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId (MiniProfilerId)
) engine=InnoDB collate utf8mb4_bin;";
}

Expand Down
34 changes: 23 additions & 11 deletions src/MiniProfiler.Providers.PostgreSql/PostgreSqlStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace StackExchange.Profiling.Storage
Expand Down Expand Up @@ -242,14 +243,14 @@ public override async Task<MiniProfiler> LoadAsync(Guid id)
}

/// <summary>
/// Sets a particular profiler session so it is considered "unviewed"
/// Sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
public override void SetUnviewed(string user, Guid id) => ToggleViewed(user, id, false);

/// <summary>
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
Expand Down Expand Up @@ -386,12 +387,23 @@ Select Id
}

/// <summary>
/// Returns a connection to Sql Server.
/// Returns a connection to PostgreSQL.
/// </summary>
protected override DbConnection GetConnection() => new NpgsqlConnection(ConnectionString);

/// <summary>
/// SQL statements to create the SQL Server tables.
/// SQL statements to create the PostgreSQL schema names.
/// </summary>
protected override IEnumerable<string> GetSchemaNameCreationScripts(IEnumerable<string> schemaNames)
{
foreach (var schemaName in schemaNames)
{
yield return $@"CREATE SCHEMA IF NOT EXISTS [{schemaName}]";
}
}

/// <summary>
/// SQL statements to create the PostgreSQL tables.
/// </summary>
protected override IEnumerable<string> GetTableCreationScripts()
{
Expand All @@ -411,10 +423,10 @@ MachineName varchar(100) null,
ClientTimingsRedirectCount integer null
);
-- displaying results selects everything based on the main MiniProfilers.Id column
CREATE UNIQUE INDEX IX_{MiniProfilersTable}_Id ON {MiniProfilersTable} (Id);
CREATE UNIQUE INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id ON {MiniProfilersTable} (Id);

-- speeds up a query that is called on every .Stop()
CREATE INDEX IX_{MiniProfilersTable}_User_HasUserViewed_Includes ON {MiniProfilersTable} (""User"", HasUserViewed);
CREATE INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_User_HasUserViewed_Includes ON {MiniProfilersTable} (""User"", HasUserViewed);

CREATE TABLE {MiniProfilerTimingsTable}
(
Expand All @@ -430,8 +442,8 @@ StartMilliseconds decimal(15,3) not null,
CustomTimingsJson varchar null
);

CREATE UNIQUE INDEX IX_{MiniProfilerTimingsTable}_Id ON {MiniProfilerTimingsTable} (Id);
CREATE INDEX IX_{MiniProfilerTimingsTable}_MiniProfilerId ON {MiniProfilerTimingsTable} (MiniProfilerId);
CREATE UNIQUE INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id ON {MiniProfilerTimingsTable} (Id);
CREATE INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId ON {MiniProfilerTimingsTable} (MiniProfilerId);

CREATE TABLE {MiniProfilerClientTimingsTable}
(
Expand All @@ -443,8 +455,8 @@ Start decimal(9, 3) not null,
Duration decimal(9, 3) not null
);

CREATE UNIQUE INDEX IX_{MiniProfilerClientTimingsTable}_Id on {MiniProfilerClientTimingsTable} (Id);
CREATE INDEX IX_{MiniProfilerClientTimingsTable}_MiniProfilerId on {MiniProfilerClientTimingsTable} (MiniProfilerId);
CREATE UNIQUE INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id on {MiniProfilerClientTimingsTable} (Id);
CREATE INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId on {MiniProfilerClientTimingsTable} (MiniProfilerId);
";
}
}
Expand Down
131 changes: 76 additions & 55 deletions src/MiniProfiler.Providers.SqlServer/SqlServerStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Data.Common;
using System.Data.SqlClient;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace StackExchange.Profiling.Storage
Expand Down Expand Up @@ -242,14 +243,14 @@ public override async Task<MiniProfiler> LoadAsync(Guid id)
}

/// <summary>
/// Sets a particular profiler session so it is considered "unviewed"
/// Sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
public override void SetUnviewed(string user, Guid id) => ToggleViewed(user, id, false);

/// <summary>
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// Asynchronously sets a particular profiler session so it is considered "unviewed"
/// </summary>
/// <param name="user">The user to set this profiler ID as unviewed for.</param>
/// <param name="id">The profiler ID to set unviewed.</param>
Expand All @@ -272,9 +273,9 @@ public override async Task<MiniProfiler> LoadAsync(Guid id)
private string _toggleViewedSql;

private string ToggleViewedSql => _toggleViewedSql ??= $@"
Update {MiniProfilersTable}
Set HasUserViewed = @hasUserVeiwed
Where Id = @id
Update {MiniProfilersTable}
Set HasUserViewed = @hasUserVeiwed
Where Id = @id
And [User] = @user";

private void ToggleViewed(string user, Guid id, bool hasUserVeiwed)
Expand Down Expand Up @@ -385,65 +386,85 @@ private string BuildListQuery(DateTime? start = null, DateTime? finish = null, L
}

/// <summary>
/// Returns a connection to Sql Server.
/// Returns a connection to SQL Server.
/// </summary>
protected override DbConnection GetConnection() => new SqlConnection(ConnectionString);

/// <summary>
/// SQL statements to create the SQL Server schema names.
/// </summary>
protected override IEnumerable<string> GetSchemaNameCreationScripts(IEnumerable<string> schemaNames)
{
foreach (var schemaName in schemaNames)
{
yield return $@"IF NOT EXISTS (SELECT * FROM sys.schemas WHERE name = N'{schemaName}') EXEC('CREATE SCHEMA [{schemaName}]');";
}
}

/// <summary>
/// SQL statements to create the SQL Server tables.
/// </summary>
protected override IEnumerable<string> GetTableCreationScripts()
{
yield return $@"
CREATE TABLE {MiniProfilersTable}
(
RowId integer not null identity constraint PK_{MiniProfilersTable} primary key clustered, -- Need a clustered primary key for SQL Azure
Id uniqueidentifier not null, -- don't cluster on a guid
RootTimingId uniqueidentifier null,
Name nvarchar(200) null,
Started datetime not null,
DurationMilliseconds decimal(15,1) not null,
[User] nvarchar(100) null,
HasUserViewed bit not null,
MachineName nvarchar(100) null,
CustomLinksJson nvarchar(max),
ClientTimingsRedirectCount int null
);
-- displaying results selects everything based on the main MiniProfilers.Id column
CREATE UNIQUE NONCLUSTERED INDEX IX_{MiniProfilersTable}_Id ON {MiniProfilersTable} (Id);

-- speeds up a query that is called on every .Stop()
CREATE NONCLUSTERED INDEX IX_{MiniProfilersTable}_User_HasUserViewed_Includes ON {MiniProfilersTable} ([User], HasUserViewed) INCLUDE (Id, [Started]);

CREATE TABLE {MiniProfilerTimingsTable}
(
RowId integer not null identity constraint PK_{MiniProfilerTimingsTable} primary key clustered,
Id uniqueidentifier not null,
MiniProfilerId uniqueidentifier not null,
ParentTimingId uniqueidentifier null,
Name nvarchar(200) not null,
DurationMilliseconds decimal(15,3) not null,
StartMilliseconds decimal(15,3) not null,
IsRoot bit not null,
Depth smallint not null,
CustomTimingsJson nvarchar(max) null
);

CREATE UNIQUE NONCLUSTERED INDEX IX_{MiniProfilerTimingsTable}_Id ON {MiniProfilerTimingsTable} (Id);
CREATE NONCLUSTERED INDEX IX_{MiniProfilerTimingsTable}_MiniProfilerId ON {MiniProfilerTimingsTable} (MiniProfilerId);

CREATE TABLE {MiniProfilerClientTimingsTable}
(
RowId integer not null identity constraint PK_{MiniProfilerClientTimingsTable} primary key clustered,
Id uniqueidentifier not null,
MiniProfilerId uniqueidentifier not null,
Name nvarchar(200) not null,
Start decimal(9, 3) not null,
Duration decimal(9, 3) not null
);

CREATE UNIQUE NONCLUSTERED INDEX IX_{MiniProfilerClientTimingsTable}_Id on {MiniProfilerClientTimingsTable} (Id);
CREATE NONCLUSTERED INDEX IX_{MiniProfilerClientTimingsTable}_MiniProfilerId on {MiniProfilerClientTimingsTable} (MiniProfilerId);
IF OBJECT_ID(N'{MiniProfilersTable}', N'U') IS NULL
BEGIN
CREATE TABLE {MiniProfilersTable}
(
RowId integer not null identity constraint PK_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")} primary key clustered, -- Need a clustered primary key for SQL Azure
Id uniqueidentifier not null, -- don't cluster on a guid
RootTimingId uniqueidentifier null,
Name nvarchar(200) null,
Started datetime not null,
DurationMilliseconds decimal(15,1) not null,
[User] nvarchar(100) null,
HasUserViewed bit not null,
MachineName nvarchar(100) null,
CustomLinksJson nvarchar(max),
ClientTimingsRedirectCount int null
);
-- displaying results selects everything based on the main MiniProfilers.Id column
CREATE UNIQUE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id ON {MiniProfilersTable} (Id);

-- speeds up a query that is called on every .Stop()
CREATE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilersTable, IndexNameWrongSymbolsReplacePattern, "_")}_User_HasUserViewed_Includes ON {MiniProfilersTable} ([User], HasUserViewed) INCLUDE (Id, [Started]);
END;

IF OBJECT_ID(N'{MiniProfilerTimingsTable}', N'U') IS NULL
BEGIN
CREATE TABLE {MiniProfilerTimingsTable}
(
RowId integer not null identity constraint PK_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")} primary key clustered,
Id uniqueidentifier not null,
MiniProfilerId uniqueidentifier not null,
ParentTimingId uniqueidentifier null,
Name nvarchar(200) not null,
DurationMilliseconds decimal(15,3) not null,
StartMilliseconds decimal(15,3) not null,
IsRoot bit not null,
Depth smallint not null,
CustomTimingsJson nvarchar(max) null
);

CREATE UNIQUE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id ON {MiniProfilerTimingsTable} (Id);
CREATE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilerTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId ON {MiniProfilerTimingsTable} (MiniProfilerId);
END;

IF OBJECT_ID(N'{MiniProfilerClientTimingsTable}', N'U') IS NULL
BEGIN
CREATE TABLE {MiniProfilerClientTimingsTable}
(
RowId integer not null identity constraint PK_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")} primary key clustered,
Id uniqueidentifier not null,
MiniProfilerId uniqueidentifier not null,
Name nvarchar(200) not null,
Start decimal(9, 3) not null,
Duration decimal(9, 3) not null
);

CREATE UNIQUE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_Id on {MiniProfilerClientTimingsTable} (Id);
CREATE NONCLUSTERED INDEX IX_{Regex.Replace(MiniProfilerClientTimingsTable, IndexNameWrongSymbolsReplacePattern, "_")}_MiniProfilerId on {MiniProfilerClientTimingsTable} (MiniProfilerId);
END;
";
}
}
Expand Down
Loading