diff options
Diffstat (limited to 'docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud')
| -rw-r--r-- | docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs | 218 | ||||
| -rw-r--r-- | docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs | 21 | 
2 files changed, 221 insertions, 18 deletions
| diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs new file mode 100644 index 0000000..02848f3 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs @@ -0,0 +1,218 @@ +using System.Diagnostics; + +namespace CrupestApi.Commons; + +public interface IColumnTypeInfo +{ +    Type GetDataType(); +    Type GetDatabaseType(); +    object ConvertToDatabase(object data); +    object ConvertFromDatabase(object databaseData); + +    void Validate(IReadOnlyDictionary<Type, IColumnTypeInfo> typeInfoMap) +    { +        var typeSet = new HashSet<Type>(); + +        IColumnTypeInfo current = this; + +        while (!typeof(BuiltinColumnTypeInfo<>).IsInstanceOfType(current)) +        { +            var dataType = GetDataType(); + +            if (typeSet.Contains(dataType)) +            { +                throw new Exception("Circular reference detected."); +            } +            typeSet.Add(dataType); + +            var databaseType = GetDatabaseType(); +            if (!typeInfoMap.ContainsKey(databaseType)) +            { +                throw new Exception("Broken type chain."); +            } + +            current = typeInfoMap[databaseType]; +        } +    } +} + +public interface IBuiltinColumnTypeInfo : IColumnTypeInfo +{ +    string GetSqlType(); +} + +public class BuiltinColumnTypeInfo<T> : IBuiltinColumnTypeInfo +{ +    private readonly string _sqlType; + +    public BuiltinColumnTypeInfo(string sqlType) +    { +        _sqlType = sqlType; +    } + +    public Type GetDataType() +    { +        return typeof(T); +    } + +    public Type GetDatabaseType() +    { +        return typeof(T); +    } + +    public string GetSqlType() +    { +        return _sqlType; +    } + +    public T ConvertToDatabase(T data) +    { +        return data; +    } + +    public T ConvertFromDatabase(T databaseData) +    { +        return databaseData; +    } + +    object IColumnTypeInfo.ConvertToDatabase(object data) +    { +        return data; +    } + +    object IColumnTypeInfo.ConvertFromDatabase(object databaseData) +    { +        return databaseData; +    } +} + +public abstract class CustomColumnTypeInfo<TDataType, TDatabaseType> : IColumnTypeInfo + where TDataType : notnull where TDatabaseType : notnull +{ + +    public Type GetDataType() +    { +        return typeof(TDataType); +    } + +    public Type GetDatabaseType() +    { +        return typeof(TDatabaseType); +    } + +    public abstract TDatabaseType ConvertToDatabase(TDataType data); +    public abstract TDataType ConvertFromDatabase(TDatabaseType databaseData); + +    object IColumnTypeInfo.ConvertToDatabase(object data) +    { +        Debug.Assert(typeof(TDataType).IsInstanceOfType(data)); +        return ConvertToDatabase((TDataType)data); +    } + +    object IColumnTypeInfo.ConvertFromDatabase(object databaseData) +    { +        Debug.Assert(typeof(TDatabaseType).IsInstanceOfType(databaseData)); +        return ConvertFromDatabase((TDatabaseType)databaseData); +    } +} + +public class ColumnTypeInfoRegistry +{ +    public static IReadOnlyList<IColumnTypeInfo> BuiltinList = new List<IColumnTypeInfo>() +    { +        new BuiltinColumnTypeInfo<char>("INTEGER"), +        new BuiltinColumnTypeInfo<short>("INTEGER"), +        new BuiltinColumnTypeInfo<int>("INTEGER"), +        new BuiltinColumnTypeInfo<long>("INTEGER"), +        new BuiltinColumnTypeInfo<float>("REAL"), +        new BuiltinColumnTypeInfo<double>("REAL"), +        new BuiltinColumnTypeInfo<string>("TEXT"), +        new BuiltinColumnTypeInfo<byte[]>("BLOB"), +    }; + + +    public static IReadOnlyList<IColumnTypeInfo> CustomList = new List<IColumnTypeInfo>() +    { +        // TODO: Add custom ones. +    }; + +    public static ColumnTypeInfoRegistry Singleton { get; } + +    static ColumnTypeInfoRegistry() +    { +        Singleton = new ColumnTypeInfoRegistry(); + +        foreach (var builtinColumnTypeInfo in BuiltinList) +        { +            Singleton.Register(builtinColumnTypeInfo); +        } + +        foreach (var customColumnTypeInfo in CustomList) +        { +            Singleton.Register(customColumnTypeInfo); +        } + +        Singleton.Validate(); +    } + + + +    private readonly List<IColumnTypeInfo> _list; +    private readonly Dictionary<Type, IColumnTypeInfo> _map; +    private bool _dirty = false; + +    public ColumnTypeInfoRegistry() +    { +        _list = new List<IColumnTypeInfo>(); +        _map = new Dictionary<Type, IColumnTypeInfo>(); +    } + +    public void Register(IColumnTypeInfo columnTypeInfo) +    { +        Debug.Assert(!_list.Contains(columnTypeInfo)); +        _list.Add(columnTypeInfo); +        _map.Add(columnTypeInfo.GetDataType(), columnTypeInfo); +        _dirty = true; +    } + +    public IColumnTypeInfo? GetByDataType(Type type) +    { +        return _map.GetValueOrDefault(type); +    } + +    public string GetSqlType(Type type) +    { +        EnsureValidity(); + +        IColumnTypeInfo? current = GetByDataType(type); +        if (current is null) +        { +            throw new Exception("Unsupported type for sql."); +        } + +        while (!typeof(IBuiltinColumnTypeInfo).IsInstanceOfType(current)) +        { +            current = GetByDataType(current.GetDatabaseType()); +            Debug.Assert(current is not null); +        } + +        return ((IBuiltinColumnTypeInfo)current).GetSqlType(); +    } + +    public void Validate() +    { +        foreach (var columnTypeInfo in _list) +        { +            columnTypeInfo.Validate(_map); +        } +    } + +    public void EnsureValidity() +    { +        if (_dirty) +        { +            Validate(); +        } +    } + +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs index d5edd13..bc4ed50 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs @@ -60,30 +60,15 @@ public class CrudService<TEntity>          }      } -    public string GetDatabaseTypeName(Type type) +    public string GetSqlType(Type type)      { -        if (type == typeof(int)) -        { -            return "INTEGER"; -        } -        else if (type == typeof(double)) -        { -            return "REAL"; -        } -        else if (type == typeof(bool)) -        { -            return "BOOLEAN"; -        } -        else -        { -            throw new DatabaseInternalException($"Type {type} is not supported."); -        } +        return ColumnTypeInfoRegistry.Singleton.GetSqlType(type);      }      public string GetCreateTableColumnSql()      {          var properties = typeof(TEntity).GetProperties(); -        var sql = string.Join(", ", properties.Select(p => $"{p.Name} {GetDatabaseTypeName(p.PropertyType)}")); +        var sql = string.Join(", ", properties.Select(p => $"{p.Name} {GetSqlType(p.PropertyType)}"));          return sql;      } | 
