aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-12-06 21:03:36 +0800
committercrupest <crupest@outlook.com>2022-12-20 20:32:52 +0800
commit1870bc78d4a2733246322c5540761da852afe713 (patch)
tree7dd05378a17e6b687af4987fe50e425171f0e07b
parentc16159d9ef9e3b3f359966d17f3aa6eb420620f6 (diff)
downloadcrupest-1870bc78d4a2733246322c5540761da852afe713.tar.gz
crupest-1870bc78d4a2733246322c5540761da852afe713.tar.bz2
crupest-1870bc78d4a2733246322c5540761da852afe713.zip
Develop secret api. v16
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs38
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs325
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs2
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs2
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs2
5 files changed, 134 insertions, 235 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
index 1754c8d..081071f 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
@@ -20,11 +20,11 @@ public class ColumnInfo
}
// A column with no property.
- public ColumnInfo(Type entityType, string sqlColumnName, bool isPrimaryKey, bool isAutoIncrement, IColumnTypeInfo typeInfo, ColumnIndexType indexType = ColumnIndexType.None, ColumnTypeInfoRegistry? typeRegistry = null)
+ public ColumnInfo(Type entityType, string sqlColumnName, bool isPrimaryKey, bool isAutoIncrement, ColumnTypeInfo typeInfo, ColumnIndexType indexType = ColumnIndexType.None, ColumnTypeRegistry? typeRegistry = null)
{
if (typeRegistry is null)
{
- typeRegistry = ColumnTypeInfoRegistry.Singleton;
+ typeRegistry = ColumnTypeRegistry.Instance;
}
EntityType = entityType;
@@ -40,11 +40,11 @@ public class ColumnInfo
IndexType = indexType;
}
- public ColumnInfo(Type entityType, string entityPropertyName, ColumnTypeInfoRegistry? typeRegistry = null)
+ public ColumnInfo(Type entityType, string entityPropertyName, ColumnTypeRegistry? typeRegistry = null)
{
if (typeRegistry is null)
{
- typeRegistry = ColumnTypeInfoRegistry.Singleton;
+ typeRegistry = ColumnTypeRegistry.Instance;
}
EntityType = entityType;
@@ -73,25 +73,8 @@ public class ColumnInfo
DefaultEmptyForString = columnAttribute.DefaultEmptyForString;
}
- ColumnTypeInfo = typeRegistry.GetRequiredByDataType(PropertyRealType);
+ ColumnTypeInfo = typeRegistry.GetRequired(PropertyRealType);
TypeRegistry = typeRegistry;
-
- if (DefaultEmptyForString)
- {
- EntityPostGet += (entity, column, _, _) =>
- {
- var pi = column.PropertyInfo;
- if (pi is not null && column.ColumnTypeInfo.GetUnderlineType() == typeof(string))
- {
- var value = pi.GetValue(entity);
- if (value is null)
- {
- pi.SetValue(entity, string.Empty);
- }
- }
- return Task.CompletedTask;
- };
- }
}
public Type EntityType { get; }
@@ -101,18 +84,17 @@ public class ColumnInfo
public Type PropertyType { get; }
public Type PropertyRealType { get; }
public string SqlColumnName { get; }
- public ColumnTypeInfoRegistry TypeRegistry { get; set; }
- public IColumnTypeInfo ColumnTypeInfo { get; }
+ public ColumnTypeRegistry TypeRegistry { get; set; }
+ public ColumnTypeInfo ColumnTypeInfo { get; }
public bool Nullable { get; }
public bool IsPrimaryKey { get; }
public bool IsAutoIncrement { get; }
public ColumnIndexType IndexType { get; }
- public bool DefaultEmptyForString { get; }
- public event EntityPreSave? EntityPreSave;
- public event EntityPostGet? EntityPostGet;
+ // TODO: Implement this behavior.
+ public bool DefaultEmptyForString { get; }
- public string SqlType => TypeRegistry.GetSqlTypeRecursive(ColumnTypeInfo);
+ public string SqlType => ColumnTypeInfo.SqlType;
public string GenerateCreateTableColumnString()
{
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
index e39be98..4e640ff 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
@@ -1,3 +1,4 @@
+using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Text.Json;
@@ -5,157 +6,148 @@ using System.Text.Json.Serialization;
namespace CrupestApi.Commons.Crud;
-public interface IColumnTypeInfo
+/// <summary> Represents a type of one column. </summary>
+public abstract class ColumnTypeInfo
{
- JsonConverter? GetOptionalJsonConverter()
+ protected ColumnTypeInfo(Type supportedType)
{
- return null;
+ SupportedType = supportedType;
}
- Type GetPropertyType();
- Type GetUnderlineType();
- object ConvertToUnderline(object data);
- object ConvertFromUnderline(object databaseData);
+ public Type SupportedType { get; }
- void Validate(IReadOnlyDictionary<Type, IColumnTypeInfo> typeInfoMap)
+ public bool IsOfSupportedType(object value)
{
- var typeSet = new HashSet<Type>();
+ return value is not null && SupportedType.IsAssignableFrom(value.GetType());
+ }
- IColumnTypeInfo current = this;
+ public abstract BasicColumnTypeInfo UnderlineType { get; }
- while (current is not IBuiltinColumnTypeInfo)
- {
- var dataType = GetPropertyType();
+ public abstract IReadOnlyList<DerivedColumnTypeInfo> DerivedTypes { get; }
- if (typeSet.Contains(dataType))
- {
- throw new Exception("Circular reference detected.");
- }
- typeSet.Add(dataType);
+ public abstract string SqlType { get; }
- var databaseType = GetUnderlineType();
- if (!typeInfoMap.ContainsKey(databaseType))
- {
- throw new Exception("Broken type chain.");
- }
+ public abstract DbType DbType { get; }
- current = typeInfoMap[databaseType];
- }
- }
-}
+ /// <summary>
+ /// An optional json converter for this type.
+ /// </summary>
+ /// <returns>The converter if this type needs a json converter. Otherwise null.</returns>
+ public abstract JsonConverter? GetJsonConverter();
-public interface IBuiltinColumnTypeInfo : IColumnTypeInfo
-{
- /// To use for non-builtin type, use <see cref="ColumnTypeInfoRegistry.GetSqlTypeRecursive(IColumnTypeInfo)" /> because we need registry to query more information.
- string GetSqlType();
- // To use for non-builtin type, use <see cref="ColumnTypeInfoRegistry.GetDbType(IColumnTypeInfo)" /> because we need registry to query more information.
- DbType GetDbType();
+ /// <summary>
+ /// Convert a value into underline type.
+ /// </summary>
+ public abstract object? ConvertToUnderline(object? value);
+
+ /// <summary>
+ /// Convert to a value of this type from value of underline type.
+ /// </summary>
+ public abstract object? ConvertFromUnderline(object? underlineValue);
}
-public class BuiltinColumnTypeInfo<T> : IBuiltinColumnTypeInfo
+public class BasicColumnTypeInfo : ColumnTypeInfo
{
+ public static BasicColumnTypeInfo<char> CharColumnTypeInfo { get; } = new BasicColumnTypeInfo<char>("INTEGER", DbType.Int32);
+ public static BasicColumnTypeInfo<short> ShortColumnTypeInfo { get; } = new BasicColumnTypeInfo<short>("INTEGER", DbType.Int32);
+ public static BasicColumnTypeInfo<int> IntColumnTypeInfo { get; } = new BasicColumnTypeInfo<int>("INTEGER", DbType.Int32);
+ public static BasicColumnTypeInfo<long> LongColumnTypeInfo { get; } = new BasicColumnTypeInfo<long>("INTEGER", DbType.Int64);
+ public static BasicColumnTypeInfo<float> FloatColumnTypeInfo { get; } = new BasicColumnTypeInfo<float>("REAL", DbType.Double);
+ public static BasicColumnTypeInfo<double> DoubleColumnTypeInfo { get; } = new BasicColumnTypeInfo<double>("REAL", DbType.Double);
+ public static BasicColumnTypeInfo<string> StringColumnTypeInfo { get; } = new BasicColumnTypeInfo<string>("TEXT", DbType.String);
+ public static BasicColumnTypeInfo<byte[]> ByteColumnTypeInfo { get; } = new BasicColumnTypeInfo<byte[]>("BLOB", DbType.Binary);
+
private readonly string _sqlType;
private readonly DbType _dbType;
+ internal List<DerivedColumnTypeInfo> _derivedTypes = new List<DerivedColumnTypeInfo>();
- public BuiltinColumnTypeInfo(string sqlType, DbType dbType)
+ public BasicColumnTypeInfo(Type type, string sqlType, DbType dbType)
+ : base(type)
{
_sqlType = sqlType;
_dbType = dbType;
}
- public Type GetPropertyType()
- {
- return typeof(T);
- }
+ public override BasicColumnTypeInfo UnderlineType => this;
- public Type GetUnderlineType()
- {
- return typeof(T);
- }
-
- public string GetSqlType()
- {
- return _sqlType;
- }
+ public override IReadOnlyList<DerivedColumnTypeInfo> DerivedTypes => _derivedTypes;
- public DbType GetDbType()
- {
- return _dbType;
- }
+ public override string SqlType => _sqlType;
- public T ConvertToDatabase(T data)
- {
- return data;
- }
+ public override DbType DbType => _dbType;
- public T ConvertFromDatabase(T databaseData)
+ public override object? ConvertToUnderline(object? value)
{
- return databaseData;
+ Debug.Assert(value is null || SupportedType.IsInstanceOfType(value));
+ return value;
}
- object IColumnTypeInfo.ConvertToUnderline(object data)
+ public override object? ConvertFromUnderline(object? underlineValue)
{
- return data;
+ Debug.Assert(underlineValue is null || SupportedType.IsInstanceOfType(underlineValue));
+ return underlineValue;
}
- object IColumnTypeInfo.ConvertFromUnderline(object databaseData)
+ public override JsonConverter? GetJsonConverter()
{
- return databaseData;
+ return null;
}
}
-public interface ICustomColumnTypeInfo : IColumnTypeInfo
+public class BasicColumnTypeInfo<T> : BasicColumnTypeInfo
{
-
+ public BasicColumnTypeInfo(string sqlType, DbType dbType) : base(typeof(T), sqlType, dbType) { }
}
-public abstract class CustomColumnTypeInfo<TPropertyType, TUnderlineType> : ICustomColumnTypeInfo
- where TPropertyType : notnull where TUnderlineType : notnull
+public abstract class DerivedColumnTypeInfo : ColumnTypeInfo
{
-
- public Type GetPropertyType()
+ protected DerivedColumnTypeInfo(Type supportedType, BasicColumnTypeInfo underlineType)
+ : base(supportedType)
{
- return typeof(TPropertyType);
+ UnderlineType = underlineType;
+ UnderlineType._derivedTypes.Add(this);
}
- public Type GetUnderlineType()
- {
- return typeof(TUnderlineType);
- }
+ public override BasicColumnTypeInfo UnderlineType { get; }
- public abstract TUnderlineType ConvertToUnderline(TPropertyType data);
- public abstract TPropertyType ConvertFromUnderline(TUnderlineType databaseData);
+ private static readonly List<DerivedColumnTypeInfo> _emptyList = new List<DerivedColumnTypeInfo>();
- object IColumnTypeInfo.ConvertToUnderline(object data)
- {
- Debug.Assert(data is TPropertyType);
- return ConvertToUnderline((TPropertyType)data);
- }
+ public override IReadOnlyList<DerivedColumnTypeInfo> DerivedTypes => _emptyList;
- object IColumnTypeInfo.ConvertFromUnderline(object databaseData)
- {
- Debug.Assert(databaseData is TUnderlineType);
- return ConvertFromUnderline((TUnderlineType)databaseData);
- }
+ public override string SqlType => UnderlineType!.SqlType;
+
+ public override DbType DbType => UnderlineType!.DbType;
}
-public class DateTimeColumnTypeInfo : CustomColumnTypeInfo<DateTime, long>
+public class DateTimeColumnTypeInfo : DerivedColumnTypeInfo
{
private readonly DateTimeJsonConverter _jsonConverter = new DateTimeJsonConverter();
- public JsonConverter GetJsonConverter()
+ public DateTimeColumnTypeInfo()
+ : base(typeof(DateTime), BasicColumnTypeInfo.LongColumnTypeInfo)
+ {
+
+ }
+
+ public override JsonConverter GetJsonConverter()
{
return _jsonConverter;
}
- public override long ConvertToUnderline(DateTime data)
+ public override object? ConvertToUnderline(object? value)
{
- return new DateTimeOffset(data).ToUnixTimeSeconds();
+ if (value is null) return null;
+
+ Debug.Assert(value is DateTime);
+ return new DateTimeOffset((DateTime)value).ToUnixTimeSeconds();
}
- public override DateTime ConvertFromUnderline(long databaseData)
+ public override object? ConvertFromUnderline(object? underlineValue)
{
- return DateTimeOffset.FromUnixTimeSeconds(databaseData).LocalDateTime;
+ if (underlineValue is null) return null;
+
+ Debug.Assert(typeof(long).IsAssignableFrom(underlineValue.GetType()));
+ return DateTimeOffset.FromUnixTimeSeconds((long)underlineValue).LocalDateTime;
}
}
@@ -179,162 +171,87 @@ public class DateTimeJsonConverter : JsonConverter<DateTime>
}
}
-public class ColumnTypeInfoRegistry
+public class ColumnTypeRegistry
{
- public static IReadOnlyList<IColumnTypeInfo> BuiltinList = new List<IColumnTypeInfo>()
- {
- new BuiltinColumnTypeInfo<char>("INTEGER", DbType.Int32),
- new BuiltinColumnTypeInfo<short>("INTEGER", DbType.Int32),
- new BuiltinColumnTypeInfo<int>("INTEGER", DbType.Int32),
- new BuiltinColumnTypeInfo<long>("INTEGER", DbType.Int64),
- new BuiltinColumnTypeInfo<float>("REAL", DbType.Double),
- new BuiltinColumnTypeInfo<double>("REAL", DbType.Double),
- new BuiltinColumnTypeInfo<string>("TEXT", DbType.String),
- new BuiltinColumnTypeInfo<byte[]>("BLOB", DbType.Binary),
- };
-
-
- public static IReadOnlyList<IColumnTypeInfo> CustomList = new List<IColumnTypeInfo>()
- {
- new DateTimeColumnTypeInfo(),
+ public static IReadOnlyList<BasicColumnTypeInfo> BasicTypeList = new List<BasicColumnTypeInfo>()
+ {
+ BasicColumnTypeInfo.CharColumnTypeInfo,
+ BasicColumnTypeInfo.ShortColumnTypeInfo,
+ BasicColumnTypeInfo.IntColumnTypeInfo,
+ BasicColumnTypeInfo.LongColumnTypeInfo,
+ BasicColumnTypeInfo.FloatColumnTypeInfo,
+ BasicColumnTypeInfo.DoubleColumnTypeInfo,
+ BasicColumnTypeInfo.StringColumnTypeInfo,
+ BasicColumnTypeInfo.ByteColumnTypeInfo,
};
- public static ColumnTypeInfoRegistry Singleton { get; }
+ public static ColumnTypeRegistry Instance { get; }
- static ColumnTypeInfoRegistry()
+ static ColumnTypeRegistry()
{
- Singleton = new ColumnTypeInfoRegistry();
-
- foreach (var builtinColumnTypeInfo in BuiltinList)
- {
- Singleton.Register(builtinColumnTypeInfo);
- }
+ Instance = new ColumnTypeRegistry();
- foreach (var customColumnTypeInfo in CustomList)
+ foreach (var basicColumnTypeInfo in BasicTypeList)
{
- Singleton.Register(customColumnTypeInfo);
+ Instance.Register(basicColumnTypeInfo);
}
- Singleton.Validate();
+ Instance.Register(new DateTimeColumnTypeInfo());
}
- private readonly List<IColumnTypeInfo> _list;
- private readonly Dictionary<Type, IColumnTypeInfo> _map;
- private bool _dirty = false;
+ private readonly List<ColumnTypeInfo> _list;
+ private readonly Dictionary<Type, ColumnTypeInfo> _map;
- public ColumnTypeInfoRegistry()
+ public ColumnTypeRegistry()
{
- _list = new List<IColumnTypeInfo>();
- _map = new Dictionary<Type, IColumnTypeInfo>();
+ _list = new List<ColumnTypeInfo>();
+ _map = new Dictionary<Type, ColumnTypeInfo>();
}
- public void Register(IColumnTypeInfo columnTypeInfo)
+ public void Register(ColumnTypeInfo columnTypeInfo)
{
Debug.Assert(!_list.Contains(columnTypeInfo));
+ Debug.Assert(!_map.ContainsKey(columnTypeInfo.SupportedType));
_list.Add(columnTypeInfo);
- _map.Add(columnTypeInfo.GetPropertyType(), columnTypeInfo);
- _dirty = true;
+ _map.Add(columnTypeInfo.SupportedType, columnTypeInfo);
}
- public IColumnTypeInfo? GetByDataType(Type type)
+ public ColumnTypeInfo? Get(Type type)
{
return _map.GetValueOrDefault(type);
}
- public IColumnTypeInfo GetRequiredByDataType(Type type)
+ public ColumnTypeInfo? Get<T>()
{
- return GetByDataType(type) ?? throw new Exception("Unsupported type.");
+ return Get(typeof(T));
}
- public string GetSqlTypeRecursive(IColumnTypeInfo columnTypeInfo)
+ public ColumnTypeInfo GetRequired(Type type)
{
- EnsureValidity();
-
- IColumnTypeInfo? current = columnTypeInfo;
- while (current is not IBuiltinColumnTypeInfo)
- {
- current = GetByDataType(current.GetUnderlineType());
- Debug.Assert(current is not null);
- }
-
- return ((IBuiltinColumnTypeInfo)current).GetSqlType();
+ return Get(type) ?? throw new Exception("Unsupported type.");
}
- public DbType GetDbTypeRecursive(IColumnTypeInfo columnTypeInfo)
+ public ColumnTypeInfo GetRequired<T>()
{
- EnsureValidity();
-
- IColumnTypeInfo? current = columnTypeInfo;
- if (current is not IBuiltinColumnTypeInfo)
- {
- current = GetByDataType(current.GetUnderlineType());
- Debug.Assert(current is not null);
- }
-
- return ((IBuiltinColumnTypeInfo)current).GetDbType();
- }
-
- public object? ConvertToUnderlineRecursive(object? value)
- {
- EnsureValidity();
-
- if (value is null)
- {
- return null;
- }
-
- IColumnTypeInfo? current = GetByDataType(value.GetType());
- if (current is null)
- {
- return value;
- }
-
- while (current is not IBuiltinColumnTypeInfo)
- {
- value = current.ConvertToUnderline(value);
- current = GetByDataType(current.GetUnderlineType());
- Debug.Assert(current is not null);
- }
-
- return value;
- }
-
- public string GetSqlType(Type type)
- {
- return GetSqlTypeRecursive(GetRequiredByDataType(type));
- }
-
- public DbType GetDbType(Type type)
- {
- return GetDbTypeRecursive(GetRequiredByDataType(type));
+ return GetRequired(typeof(T));
}
public object? ConvertToUnderline(object? value)
{
- return ConvertToUnderlineRecursive(value);
- }
+ if (value is null) return null;
- public void Validate()
- {
- foreach (var columnTypeInfo in _list)
- {
- columnTypeInfo.Validate(_map);
- }
- }
+ var type = value.GetType();
+ var columnTypeInfo = Get(type);
+ if (columnTypeInfo is null) throw new Exception("Unsupported type.");
- public void EnsureValidity()
- {
- if (_dirty)
- {
- Validate();
- }
+ return columnTypeInfo.ConvertToUnderline(value);
}
public IEnumerable<JsonConverter> GetJsonConverters()
{
foreach (var columnTypeInfo in _list)
{
- var converter = columnTypeInfo.GetOptionalJsonConverter();
+ var converter = columnTypeInfo.GetJsonConverter();
if (converter is not null)
yield return converter;
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
index c58897c..ac02226 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
@@ -42,7 +42,7 @@ public class TableInfo
if (!hasPrimaryKey)
{
if (hasId) throw new Exception("A column named id already exists but is not primary key.");
- var columnInfo = new ColumnInfo(entityType, "id", true, true, ColumnTypeInfoRegistry.Singleton.GetRequiredByDataType(typeof(int)));
+ var columnInfo = new ColumnInfo(entityType, "id", true, true, ColumnTypeRegistry.Instance.GetRequired<int>());
columnInfos.Add(columnInfo);
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
index ba1a28c..26dc306 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
@@ -57,7 +57,7 @@ public static class DynamicParametersExtensions
public static string AddRandomNameParameter(this DynamicParameters parameters, object? value)
{
var parameterName = IWhereClause.GenerateRandomParameterName(parameters);
- parameters.Add(parameterName, ColumnTypeInfoRegistry.Singleton.ConvertToUnderlineRecursive(value));
+ parameters.Add(parameterName, ColumnTypeRegistry.Instance.ConvertToUnderline(value));
return parameterName;
}
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
index bbb6efe..76746b4 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
@@ -14,7 +14,7 @@ public static class CrupestApiJsonExtensions
config.AllowTrailingCommas = true;
config.PropertyNameCaseInsensitive = true;
config.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
- foreach (var converter in ColumnTypeInfoRegistry.Singleton.GetJsonConverters())
+ foreach (var converter in ColumnTypeRegistry.Instance.GetJsonConverters())
{
config.Converters.Add(converter);
}