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 |