diff options
5 files changed, 102 insertions, 54 deletions
| diff --git a/docker/crupest-api/CrupestApi/.gitignore b/docker/crupest-api/CrupestApi/.gitignore index f3d2489..371ea59 100644 --- a/docker/crupest-api/CrupestApi/.gitignore +++ b/docker/crupest-api/CrupestApi/.gitignore @@ -1,3 +1,4 @@ +.vs  obj  bin  dev-config.json diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs index 8b4607d..b76e1ae 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs @@ -1,4 +1,5 @@  using System.Reflection; +using System.Text;  namespace CrupestApi.Commons.Crud; @@ -15,8 +16,13 @@ public class ColumnInfo      }      // A column with no property. -    public ColumnInfo(Type entityType, string sqlColumnName, bool isPrimaryKey, bool isAutoIncrement, IColumnTypeInfo typeInfo) +    public ColumnInfo(Type entityType, string sqlColumnName, bool isPrimaryKey, bool isAutoIncrement, IColumnTypeInfo typeInfo, ColumnTypeInfoRegistry? typeRegistry = null)      { +        if (typeRegistry is null) +        { +            typeRegistry = ColumnTypeInfoRegistry.Singleton; +        } +          EntityType = entityType;          PropertyName = null;          PropertyType = typeof(int); @@ -26,10 +32,16 @@ public class ColumnInfo          Nullable = false;          IsPrimaryKey = isPrimaryKey;          IsAutoIncrement = isAutoIncrement; +        TypeRegistry = typeRegistry;      } -    public ColumnInfo(Type entityType, string entityPropertyName) +    public ColumnInfo(Type entityType, string entityPropertyName, ColumnTypeInfoRegistry? typeRegistry = null)      { +        if (typeRegistry is null) +        { +            typeRegistry = ColumnTypeInfoRegistry.Singleton; +        } +          EntityType = entityType;          PropertyName = entityPropertyName; @@ -52,8 +64,9 @@ public class ColumnInfo              SqlColumnName = columnAttribute.DatabaseName ?? PropertyName;              Nullable = !columnAttribute.NonNullable;          } -        ColumnTypeInfo = ColumnTypeInfoRegistry.Singleton.GetRequiredByDataType(PropertyRealType); +        ColumnTypeInfo = typeRegistry.GetRequiredByDataType(PropertyRealType); +        TypeRegistry = typeRegistry;      }      public Type EntityType { get; } @@ -62,8 +75,37 @@ 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 bool Nullable { get; }      public bool IsPrimaryKey { get; }      public bool IsAutoIncrement { get; } -}
\ No newline at end of file + +    public string SqlType => TypeRegistry.GetSqlType(ColumnTypeInfo); + +    public string GenerateCreateTableColumnString() +    { +        StringBuilder result = new StringBuilder(); +        result.Append(SqlColumnName); +        result.Append(' '); +        result.Append(SqlType); +        if (IsPrimaryKey) +        { +            result.Append(' '); +            result.Append("PRIMARY KEY"); +        } +        else if (!Nullable) +        { +            result.Append(' '); +            result.Append(" NOT NULL"); +        } + +        if (IsAutoIncrement) +        { +            result.Append(' '); +            result.Append("AUTOINCREMENT"); +        } + +        return result.ToString(); +    } +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs index 1bdc9c0..ff8ccea 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs @@ -38,6 +38,7 @@ public interface IColumnTypeInfo  public interface IBuiltinColumnTypeInfo : IColumnTypeInfo  { +    /// To use for non-builtin type, use <see cref="ColumnTypeInfoRegistry.GetSqlType(IColumnTypeInfo)" /> because we need registry to query more information.       string GetSqlType();  } @@ -188,11 +189,11 @@ public class ColumnTypeInfoRegistry          return GetByDataType(type) ?? throw new Exception("Unsupported type.");      } -    public string GetSqlType(Type type) +    public string GetSqlType(IColumnTypeInfo columnTypeInfo)      {          EnsureValidity(); -        IColumnTypeInfo? current = GetByDataType(type); +        IColumnTypeInfo? current = columnTypeInfo;          if (current is null)          {              throw new Exception("Unsupported type for sql."); @@ -207,6 +208,11 @@ public class ColumnTypeInfoRegistry          return ((IBuiltinColumnTypeInfo)current).GetSqlType();      } +    public string GetSqlType(Type type) +    { +        return GetSqlType(GetRequiredByDataType(type)); +    } +      public void Validate()      {          foreach (var columnTypeInfo in _list) diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs index bc4ed50..63a247b 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs @@ -7,20 +7,17 @@ namespace CrupestApi.Commons.Crud;  public class CrudService<TEntity>  { +    protected readonly TableInfo _table;      protected readonly IOptionsSnapshot<CrupestApiConfig> _crupestApiOptions;      protected readonly ILogger<CrudService<TEntity>> _logger;      public CrudService(IOptionsSnapshot<CrupestApiConfig> crupestApiOptions, ILogger<CrudService<TEntity>> logger)      { +        _table = new TableInfo(typeof(TEntity));          _crupestApiOptions = crupestApiOptions;          _logger = logger;      } -    public virtual string GetTableName() -    { -        return typeof(TEntity).Name; -    } -      public virtual string GetDbConnectionString()      {          var fileName = Path.Combine(_crupestApiOptions.Value.DataDir, "crupest-api.db"); @@ -40,57 +37,17 @@ public class CrudService<TEntity>          return connection;      } -    public virtual async Task<bool> CheckDatabaseExist(SqliteConnection connection) -    { -        var tableName = GetTableName(); -        var count = (await connection.QueryAsync<int>( -            @"SELECT count(*) FROM sqlite_schema WHERE type = 'table' AND tbl_name = @TableName;", -            new { TableName = tableName })).Single(); -        if (count == 0) -        { -            return false; -        } -        else if (count > 1) -        { -            throw new DatabaseInternalException($"More than 1 table has name {tableName}. What happened?"); -        } -        else -        { -            return true; -        } -    } - -    public string GetSqlType(Type type) -    { -        return ColumnTypeInfoRegistry.Singleton.GetSqlType(type); -    } - -    public string GetCreateTableColumnSql() -    { -        var properties = typeof(TEntity).GetProperties(); -        var sql = string.Join(", ", properties.Select(p => $"{p.Name} {GetSqlType(p.PropertyType)}")); -        return sql; -    } -      public virtual async Task DoInitializeDatabase(SqliteConnection connection)      {          await using var transaction = await connection.BeginTransactionAsync(); -        var tableName = GetTableName(); -        var columnSql = GetCreateTableColumnSql(); -        var sql = $@" -CREATE TABLE {tableName}( -    id INTEGER PRIMARY KEY AUTOINCREMENT, -    {columnSql} -); -        "; -        await connection.ExecuteAsync(sql, transaction: transaction); +        await connection.ExecuteAsync(_table.GenerateCreateTableSql(), transaction: transaction);          await transaction.CommitAsync();      }      public virtual async Task<SqliteConnection> EnsureDatabase()      {          var connection = await CreateDbConnection(); -        var exist = await CheckDatabaseExist(connection); +        var exist = await _table.CheckExistence(connection);          if (!exist)          {              await DoInitializeDatabase(connection); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs index fb9e1ad..660cd4d 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs @@ -1,9 +1,20 @@ +using Dapper; +using Microsoft.Data.Sqlite; +  namespace CrupestApi.Commons.Crud;  public class TableInfo  { +    // For custom name.      public TableInfo(Type entityType) +        : this(entityType.Name, entityType) +    { + +    } + +    public TableInfo(string tableName, Type entityType)      { +        TableName = tableName;          EntityType = entityType;          var properties = entityType.GetProperties(); @@ -38,6 +49,7 @@ public class TableInfo      }      public Type EntityType { get; } +    public string TableName { get; }      public IReadOnlyList<ColumnInfo> ColumnInfos { get; }      public void CheckValidity() @@ -68,6 +80,36 @@ public class TableInfo      public string GenerateCreateTableSql()      { -        throw new NotImplementedException(); +        var tableName = TableName; +        var columnSql = string.Join(",\n", ColumnInfos.Select(c => c.GenerateCreateTableColumnString())); + +        var sql = $@" +CREATE TABLE {tableName}( +    {columnSql} +); +        "; + +        return sql; +    } + +    public async Task<bool> CheckExistence(SqliteConnection connection) +    { +        var tableName = TableName; +        var count = (await connection.QueryAsync<int>( +            @"SELECT count(*) FROM sqlite_schema WHERE type = 'table' AND tbl_name = @TableName;", +            new { TableName = tableName })).Single(); +        if (count == 0) +        { +            return false; +        } +        else if (count > 1) +        { +            throw new DatabaseInternalException($"More than 1 table has name {tableName}. What happened?"); +        } +        else +        { +            return true; +        } +      }  }
\ No newline at end of file | 
