Kit.Core/LibExternal/Npgsql/NameTranslation/NpgsqlSnakeCaseNameTranslat...

108 lines
3.6 KiB
C#

using System;
using System.Globalization;
using System.Linq;
using System.Text;
namespace Npgsql.NameTranslation;
/// <summary>
/// A name translator which converts standard CLR names (e.g. SomeClass) to snake-case database
/// names (some_class)
/// </summary>
public class NpgsqlSnakeCaseNameTranslator : INpgsqlNameTranslator
{
/// <summary>
/// Creates a new <see cref="NpgsqlSnakeCaseNameTranslator"/>.
/// </summary>
public NpgsqlSnakeCaseNameTranslator()
: this(false) { }
/// <summary>
/// Creates a new <see cref="NpgsqlSnakeCaseNameTranslator"/>.
/// </summary>
/// <param name="legacyMode">
/// Uses the legacy naming convention if <see langword="true"/>, otherwise it uses the new naming convention.
/// </param>
public NpgsqlSnakeCaseNameTranslator(bool legacyMode)
=> LegacyMode = legacyMode;
bool LegacyMode { get; }
/// <summary>
/// Given a CLR type name (e.g class, struct, enum), translates its name to a database type name.
/// </summary>
public string TranslateTypeName(string clrName) => TranslateMemberName(clrName);
/// <summary>
/// Given a CLR member name (property or field), translates its name to a database type name.
/// </summary>
public string TranslateMemberName(string clrName)
{
if (clrName == null)
throw new ArgumentNullException(nameof(clrName));
return LegacyMode
? string.Concat(clrName.Select((c, i) => i > 0 && char.IsUpper(c) ? "_" + c.ToString() : c.ToString())).ToLower()
: ConvertToSnakeCase(clrName);
}
/// <summary>
/// Converts a string to its snake_case equivalent.
/// </summary>
/// <param name="name">The value to convert.</param>
public static string ConvertToSnakeCase(string name)
{
if (string.IsNullOrEmpty(name))
return name;
var builder = new StringBuilder(name.Length + Math.Min(2, name.Length / 5));
var previousCategory = default(UnicodeCategory?);
for (var currentIndex = 0; currentIndex < name.Length; currentIndex++)
{
var currentChar = name[currentIndex];
if (currentChar == '_')
{
builder.Append('_');
previousCategory = null;
continue;
}
var currentCategory = char.GetUnicodeCategory(currentChar);
switch (currentCategory)
{
case UnicodeCategory.UppercaseLetter:
case UnicodeCategory.TitlecaseLetter:
if (previousCategory == UnicodeCategory.SpaceSeparator ||
previousCategory == UnicodeCategory.LowercaseLetter ||
previousCategory != UnicodeCategory.DecimalDigitNumber &&
previousCategory != null &&
currentIndex > 0 &&
currentIndex + 1 < name.Length &&
char.IsLower(name[currentIndex + 1]))
{
builder.Append('_');
}
currentChar = char.ToLower(currentChar);
break;
case UnicodeCategory.LowercaseLetter:
case UnicodeCategory.DecimalDigitNumber:
if (previousCategory == UnicodeCategory.SpaceSeparator)
builder.Append('_');
break;
default:
if (previousCategory != null)
previousCategory = UnicodeCategory.SpaceSeparator;
continue;
}
builder.Append(currentChar);
previousCategory = currentCategory;
}
return builder.ToString();
}
}