Skip to content
Merged
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
38 changes: 34 additions & 4 deletions MsSql.ClassGenerator.Cli/Program.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
using System.Diagnostics;
using System.Reflection;
using MsSql.ClassGenerator.Cli.Model;
using MsSql.ClassGenerator.Cli.Model;
using MsSql.ClassGenerator.Core.Business;
using MsSql.ClassGenerator.Core.Common;
using MsSql.ClassGenerator.Core.Model;
using Serilog;
using Serilog.Events;
using System.Diagnostics;
using System.Reflection;

namespace MsSql.ClassGenerator.Cli;

Expand All @@ -21,6 +20,8 @@ internal static class Program
/// <returns>The awaitable task.</returns>
private static async Task Main(string[] args)
{
await CheckForUpdate();

var argResult = args.ExtractArguments(out Arguments arguments);

Helper.InitLog(arguments.LogLevel, true);
Expand Down Expand Up @@ -98,4 +99,33 @@ private static void PrintFooterHeader(bool header)
if (header)
Log.Information("Version: {version}", Assembly.GetExecutingAssembly().GetName().Version);
}

/// <summary>
/// Checks if an update is available.
/// </summary>
/// <returns>The awaitable task.</returns>
private static async Task CheckForUpdate()
{
try
{
await UpdateHelper.LoadReleaseInfoAsync(releaseInfo =>
{
var updateMessage = $"Update available. New version: {releaseInfo.NewVersion}";
const string link = $"Link: {UpdateHelper.GitHupUrl}";

var maxLength = updateMessage.Length > link.Length ? updateMessage.Length : link.Length;

var line = "-".PadRight(maxLength + 2, '-'); // Add two for the spacer
Console.WriteLine($"+{line}+");
Console.WriteLine($"| {updateMessage.PadRight(maxLength, ' ')} |");
Console.WriteLine($"| {link.PadRight(maxLength, ' ')} |");
Console.WriteLine($"+{line}+");
Console.WriteLine();
});
}
catch
{
// Ignore
}
}
}
86 changes: 84 additions & 2 deletions MsSql.ClassGenerator.Core/Business/ClassManager.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using MsSql.ClassGenerator.Core.Common;
using System.Reflection.Emit;
using System.Text;
using MsSql.ClassGenerator.Core.Common;
using MsSql.ClassGenerator.Core.Model;
using Serilog;

Expand All @@ -12,7 +14,15 @@ public partial class ClassManager
/// <summary>
/// Occurs when progress was made.
/// </summary>
public event EventHandler<string>? ProgressEvent;
public event EventHandler<string>? ProgressEvent;

/// <summary>
/// Gets the EF Key code.
/// </summary>
/// <remarks>
/// <b>Note</b>: The code is only generated when the option <see cref="ClassGeneratorOptions.DbModel"/> is set to <see langword="true"/>.
/// </remarks>
public EfKeyCodeResult EfKeyCode { get; private set; } = new();

/// <summary>
/// Generates the classes out of the specified tables according to the specified options.
Expand All @@ -23,6 +33,8 @@ public partial class ClassManager
/// <exception cref="DirectoryNotFoundException">Will be thrown when the specified output directory doesn't exist.</exception>
public async Task GenerateClassAsync(ClassGeneratorOptions options, List<TableEntry> tables)
{
EfKeyCode = new EfKeyCodeResult();

// Step 0: Check the options.
if (!Directory.Exists(options.Output))
throw new DirectoryNotFoundException($"The specified output ({options.Output}) folder doesn't exist.");
Expand All @@ -40,6 +52,10 @@ public async Task GenerateClassAsync(ClassGeneratorOptions options, List<TableEn
Log.Debug("Generate class for table '{name}'...", table.Name);
await GenerateClassAsync(options, table);
}

// Generate the EF Key code
if (options.DbModel)
GenerateEfKeyCode(tables);
}

/// <summary>
Expand Down Expand Up @@ -248,4 +264,70 @@ private static string GetPropertyAttributes(ClassGeneratorOptions options, Colum

return string.Join(Environment.NewLine, attributes.OrderBy(o => o.Key).Select(s => s.Value));
}

/// <summary>
/// Generates the EF Key code.
/// </summary>
/// <param name="tables">The list with the tables.</param>
private void GenerateEfKeyCode(List<TableEntry> tables)
{
// Get all tables which contains more than one key column
var tmpTables = tables.Where(w => w.Columns.Count(c => c.IsPrimaryKey) > 1).ToList();
if (tmpTables.Count == 0)
return;

var sb = PrepareStringBuilder();
var count = 1;
foreach (var tableEntry in tmpTables)
{
// Add the entity
sb.AppendLine($"{Tab}modelBuilder.Entity<{tableEntry.ClassName}>().HasKey(k => new")
.AppendLine($"{Tab}{{");

// Get the key columns
var columnCount = 1;
var columns = tableEntry.Columns.Where(w => w.IsPrimaryKey).ToList();
foreach (var columnEntry in columns)
{
var comma = columnCount++ != columns.Count ? "," : string.Empty;

sb.AppendLine($"{Tab}{Tab}k.{columnEntry.PropertyName}{comma}");
}

// Add the closing brackets
sb.AppendLine($"{Tab}}});");

if (count++ != tmpTables.Count)
sb.AppendLine(); // Spacer

}

EfKeyCode = new EfKeyCodeResult
{
Code = FinalizeStringBuilder(),
TableCount = tmpTables.Count
};

return;

StringBuilder PrepareStringBuilder()
{
var stringBuilder = new StringBuilder()
.AppendLine("/// <inheritdoc />")
.AppendLine("protected override void OnModelCreating(ModelBuilder modelBuilder)")
.AppendLine("{");

return stringBuilder;
}

// Adds the final code
string FinalizeStringBuilder()
{
sb.AppendLine("}");

return sb.ToString();
}
}


}
77 changes: 77 additions & 0 deletions MsSql.ClassGenerator.Core/Business/UpdateHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using MsSql.ClassGenerator.Core.Model;
using RestSharp;
using RestSharp.Serializers.NewtonsoftJson;
using Serilog;
using System.Reflection;

namespace MsSql.ClassGenerator.Core.Business;

/// <summary>
/// Provides the functions for the update.
/// </summary>
public static class UpdateHelper
{
/// <summary>
/// Contains the URL of the latest release of the app.
/// </summary>
public const string GitHupUrl = "https://github.com/InvaderZim85/MsSql.ClassGenerator/releases/latest";

/// <summary>
/// Contains the URL of the latest release for the REST call.
/// </summary>
private const string GitHupApiUrl =
"https://api.github.com/repos/InvaderZim85/MsSql.ClassGenerator/releases/latest";

/// <summary>
/// Loads the release info of the latest release to determine if there is a new version.
/// </summary>
/// <param name="callback">Will be executed when there is a new version.</param>
/// <returns>The awaitable task.</returns>
public static async Task LoadReleaseInfoAsync(Action<ReleaseInfo> callback)
{
try
{
var client = new RestClient(GitHupApiUrl,
configureSerialization: s => s.UseNewtonsoftJson());

client.AddDefaultHeader("accept", "application/vnd.github.v3+json");

var request = new RestRequest();
var response = await client.GetAsync<ReleaseInfo>(request);

// This method also checks if the response is null
if (IsNewVersionAvailable(response))
callback(response!);
}
catch (Exception ex)
{
Log.Warning(ex, "Error while loading the latest release info.");
}
}

/// <summary>
/// Checks if an update is available
/// </summary>
/// <param name="releaseInfo">The infos of the latest release</param>
/// <returns><see langword="true"/> when there is a new version, otherwise <see langword="false"/></returns>
private static bool IsNewVersionAvailable(ReleaseInfo? releaseInfo)
{
if (releaseInfo == null)
return false;

if (!Version.TryParse(releaseInfo.TagName.Replace("v", ""), out var releaseVersion))
{
Log.Warning("Can't determine version of the latest release. Tag value: {value}", releaseInfo.TagName);
return false;
}

var currentVersion = Assembly.GetExecutingAssembly().GetName().Version;
if (currentVersion == null)
return false;

releaseInfo.CurrentVersion = currentVersion;
releaseInfo.NewVersion = releaseVersion;

return releaseInfo.UpdateAvailable;
}
}
20 changes: 20 additions & 0 deletions MsSql.ClassGenerator.Core/Common/Extensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,24 @@ public static bool StartsWithNumber(this string value)
{
return !string.IsNullOrWhiteSpace(value) && int.TryParse(value[0].ToString(), out _);
}

/// <summary>
/// Converts the value into a readable size
/// </summary>
/// <param name="value">The value</param>
/// <param name="divider">The divider (optional)</param>
/// <returns>The converted size</returns>
public static string ConvertSize(this long value, int divider = 1024)
{
return value switch
{
_ when value < divider => $"{value:N0} Bytes",
_ when value >= divider && value < Math.Pow(divider, 2) => $"{value / divider:N2} KB",
_ when value >= Math.Pow(divider, 2) && value < Math.Pow(divider, 3) =>
$"{value / Math.Pow(divider, 2):N2} MB",
_ when value >= Math.Pow(divider, 3) && value <= Math.Pow(divider, 4) => $"{value / Math.Pow(divider, 3):N2} GB",
_ when value >= Math.Pow(divider, 4) => $"{value / Math.Pow(divider, 4)} TB",
_ => value.ToString("N0")
};
}
}
18 changes: 18 additions & 0 deletions MsSql.ClassGenerator.Core/Common/Helper.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Newtonsoft.Json;
using Serilog;
using Serilog.Events;
using System.Diagnostics;

namespace MsSql.ClassGenerator.Core.Common;

Expand Down Expand Up @@ -90,4 +91,21 @@ public static List<string> GetModifierList()
"protected internal"
];
}

/// <summary>
/// Opens the specified link
/// </summary>
/// <param name="url">The url of the link</param>
public static void OpenLink(string url)
{
try
{
url = url.Replace("&", "^&");
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") { CreateNoWindow = true });
}
catch
{
// Ignore
}
}
}
2 changes: 1 addition & 1 deletion MsSql.ClassGenerator.Core/Data/BaseRepo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ protected SqlConnection GetConnection()
DataSource = server,
IntegratedSecurity = true,
TrustServerCertificate = true,
ApplicationName = nameof(MsSql.ClassGenerator)
ApplicationName = nameof(ClassGenerator)
};

if (!string.IsNullOrWhiteSpace(database))
Expand Down
32 changes: 32 additions & 0 deletions MsSql.ClassGenerator.Core/Model/Asset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using MsSql.ClassGenerator.Core.Common;
using Newtonsoft.Json;

namespace MsSql.ClassGenerator.Core.Model;

/// <summary>
/// Represents the assets of the last release
/// </summary>
public sealed class Asset
{
/// <summary>
/// Gets or sets the name of the zip file
/// </summary>
public string Name { get; set; } = string.Empty;

/// <summary>
/// Gets or sets the size of the latest release (in bytes)
/// </summary>
public long Size { get; set; }

/// <summary>
/// Gets the size of the latest release in a readable format
/// </summary>
[JsonIgnore]
public string SizeView => Size.ConvertSize();

/// <summary>
/// Gets or sets the url of the release
/// </summary>
[JsonProperty("browser_download_url")]
public string DownloadUrl { get; set; } = string.Empty;
}
22 changes: 22 additions & 0 deletions MsSql.ClassGenerator.Core/Model/EfKeyCodeResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace MsSql.ClassGenerator.Core.Model;

/// <summary>
/// Provides the key code result.
/// </summary>
public sealed class EfKeyCodeResult
{
/// <summary>
/// Gets the code.
/// </summary>
public string Code { get; init; } = string.Empty;

/// <summary>
/// Gets the amount of tables which contains multiple keys.
/// </summary>
public int TableCount { get; init; }

/// <summary>
/// Gets the value which indicates whether the code is empty.
/// </summary>
public bool IsEmpty => string.IsNullOrWhiteSpace(Code);
}
Loading