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

Post-migration actions and post-migration database views refreshing #112

Merged
merged 12 commits into from
Jan 14, 2025
Merged
2 changes: 1 addition & 1 deletion src/Kros.KORM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFrameworks>net8.0</TargetFrameworks>
<Version>7.0.0</Version>
<Version>7.1.0</Version>
<Authors>KROS a. s.</Authors>
<Company>KROS a. s.</Company>
<Description>KORM is fast, easy to use, micro ORM tool (Kros Object Relation Mapper).</Description>
Expand Down
40 changes: 39 additions & 1 deletion src/Migrations/MigrationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
using Kros.KORM.Migrations.Providers;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Kros.KORM.Migrations
{
Expand All @@ -11,14 +14,23 @@ namespace Kros.KORM.Migrations
public class MigrationOptions
{
private const int DefaultTimeoutInSeconds = 30;
private const string DefaultResourceNamespace = "Resources";
private const string DefaultRefreshViewsScriptName = "RefreshViews.sql";

private List<IMigrationScriptsProvider> _providers = new List<IMigrationScriptsProvider>();
private List<IMigrationScriptsProvider> _providers = [];
private List<Func<IDatabase, long, Task>> _actions = [];

/// <summary>
/// List of <see cref="IMigrationScriptsProvider"/>.
/// </summary>
public IEnumerable<IMigrationScriptsProvider> Providers => _providers;


/// <summary>
/// List of actions to be executed on database after migration scripts are executed.
/// </summary>
public IEnumerable<Func<IDatabase, long, Task>> Actions => _actions;

/// <summary>
/// Timeout for the migration script command.
/// If not set, default value 30s will be used.
Expand Down Expand Up @@ -46,5 +58,31 @@ public void AddAssemblyScriptsProvider(Assembly assembly, string resourceNamespa
/// <param name="folderPath">Path to folder where migration scripts are stored.</param>
public void AddFileScriptsProvider(string folderPath)
=> AddScriptsProvider(new FileMigrationScriptsProvider(folderPath));

/// <summary>
/// Add action to be executed on database after migration scripts are executed.
/// </summary>
/// <param name="actionToExecute"></param>
public void AddAfterMigrationAction(Func<IDatabase, long, Task> actionToExecute)
{
_actions.Add(actionToExecute);
}

/// <summary>
/// Add action of refreshing all database views.
/// </summary>
/// <param name="scriptName">Name of the script containing query for refreshing all views. Default one is Kros.KORM\Resources\RefreshViews.sql </param>
public void AddRefreshViewsAction(string scriptName = DefaultRefreshViewsScriptName)
mchlkntrv marked this conversation as resolved.
Show resolved Hide resolved
{
var assembly = Assembly.GetExecutingAssembly();
var resourceName = $"{assembly.GetName().Name}.{DefaultResourceNamespace}.{scriptName}";
AddAfterMigrationAction(async (database, _) =>
{
Stream resourceStream = assembly.GetManifestResourceStream(resourceName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nejdem to teraz overovať, ale mám pocit, že GetManifestResourceStream vracia nullabe stream, čiže by si mala použiť Stream?. Ak je to tak tak prosím ešte over či je to null a ak áno tak vyhoď InvalidOperationException.

A rovnako použi prosím using Stream? .... Pretože aj Stream je disposable.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pri jednom aj druhom usingu podľa mňa môžeš použiť await using miesto using. Ale istý som si není, neskúšal som to. Prosím skús.

using var reader = new StreamReader(resourceStream, Encoding.UTF8);
string script = await reader.ReadToEndAsync();
await database.ExecuteNonQueryAsync(script);
});
}
}
}
6 changes: 6 additions & 0 deletions src/Migrations/MigrationsRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ public async Task MigrateAsync()
if (migrationScripts.Any())
{
await ExecuteMigrationScripts(helper.Database, migrationScripts);
long maxScriptId = migrationScripts.Max(s => s.Id);

foreach (var action in _migrationOptions.Actions)
{
await action(helper.Database, maxScriptId);
}
}
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/RefreshViews.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
DECLARE @sql NVARCHAR(MAX)
mchlkntrv marked this conversation as resolved.
Show resolved Hide resolved

SET @sql = (
SELECT STRING_AGG('EXEC sp_refreshview ' + QUOTENAME(name), '; ')
FROM sys.views
)

EXEC sp_executesql @sql