diff options
| author | crupest <crupest@outlook.com> | 2022-12-10 20:24:59 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2022-12-20 20:32:53 +0800 | 
| commit | c2e7d3c222fcbfcce9c9a0b44dd7e82742e9cd1f (patch) | |
| tree | cd901fb537367c3340d47ccd537c4ae06b9af337 /docker/crupest-api/CrupestApi/CrupestApi.Commons | |
| parent | 4f96f8db974fa7a236ce8ffa564bccdb62691cfa (diff) | |
| download | crupest-c2e7d3c222fcbfcce9c9a0b44dd7e82742e9cd1f.tar.gz crupest-c2e7d3c222fcbfcce9c9a0b44dd7e82742e9cd1f.tar.bz2 crupest-c2e7d3c222fcbfcce9c9a0b44dd7e82742e9cd1f.zip  | |
Develop secret api. v25
Diffstat (limited to 'docker/crupest-api/CrupestApi/CrupestApi.Commons')
8 files changed, 151 insertions, 27 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs index f1fb99b..545397d 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs @@ -158,6 +158,12 @@ public class ColumnInfo      public bool IsNotNull => IsPrimaryKey || Metadata.GetValueOrDefault(ColumnMetadataKeys.NotNull) is true;      public bool IsClientGenerate => Metadata.GetValueOrDefault(ColumnMetadataKeys.ClientGenerate) is true;      public bool IsNoUpdate => Metadata.GetValueOrDefault(ColumnMetadataKeys.NoUpdate) is true; +    /// <summary> +    /// This only returns metadata value. It doesn't not fall back to primary column. If you want to get the real key column, go to table info. +    /// </summary> +    /// <seealso cref="ColumnMetadataKeys.ActAsKey"/> +    /// <seealso cref="TableInfo.KeyColumn"/> +    public bool IsSpecifiedAsKey => Metadata.GetValueOrDefault(ColumnMetadataKeys.ActAsKey) is true;      public ColumnIndexType Index => Metadata.GetValueOrDefault<ColumnIndexType?>(ColumnMetadataKeys.Index) ?? ColumnIndexType.None; diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs index 1ca2ce8..9fb3999 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs @@ -29,6 +29,11 @@ public static class ColumnMetadataKeys      /// </summary>      /// <returns></returns>      public const string NoUpdate = nameof(ColumnAttribute.NoUpdate); + +    /// <summary> +    /// This column acts as key when get one entity for http get method in path.  +    /// </summary> +    public const string ActAsKey = nameof(ColumnAttribute.ActAsKey);  }  public interface IColumnMetadata @@ -105,6 +110,11 @@ public class ColumnAttribute : Attribute, IColumnMetadata      /// <see cref="ColumnMetadataKeys.NoUpdate"/>      public bool NoUpdate { get; init; } +    /// <see cref="ColumnMetadataKeys.ActAsKey"/> +    public bool ActAsKey { get; init; } + + +      public bool TryGetValue(string key, out object? value)      {          var property = GetType().GetProperty(key); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs index 811b2e6..af6a8d5 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs @@ -1,13 +1,16 @@  using System.Data; +using System.Text.Json;  using Dapper;  namespace CrupestApi.Commons.Crud; +// TODO: Register this.  public class CrudService<TEntity> : IDisposable where TEntity : class  {      protected readonly TableInfo _table;      protected readonly string? _connectionName;      protected readonly IDbConnection _dbConnection; +    protected readonly EntityJsonHelper _jsonHelper;      private readonly ILogger<CrudService<TEntity>> _logger;      public CrudService(string? connectionName, ITableInfoFactory tableInfoFactory, IDbConnectionFactory dbConnectionFactory, ILoggerFactory loggerFactory) @@ -15,6 +18,7 @@ public class CrudService<TEntity> : IDisposable where TEntity : class          _connectionName = connectionName;          _table = tableInfoFactory.Get(typeof(TEntity));          _dbConnection = dbConnectionFactory.Get(_connectionName); +        _jsonHelper = new EntityJsonHelper(_table);          _logger = loggerFactory.CreateLogger<CrudService<TEntity>>();          if (!_table.CheckExistence(_dbConnection)) @@ -50,12 +54,14 @@ public class CrudService<TEntity> : IDisposable where TEntity : class          return _table.SelectCount(_dbConnection, filter);      } -    public int Insert(IInsertClause insertClause) +    // Return the key. +    public object Insert(IInsertClause insertClause)      {          return _table.Insert(_dbConnection, insertClause);      } -    public int Insert(TEntity entity) +    // Return the key. +    public object Insert(TEntity entity)      {          return _table.Insert(_dbConnection, _table.GenerateInsertClauseFromEntity(entity));      } @@ -69,4 +75,25 @@ public class CrudService<TEntity> : IDisposable where TEntity : class      {          return _table.Delete(_dbConnection, filter);      } + +    public TEntity SelectByKey(object key) +    { +        return Select(WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key)).Single(); +    } + +    public List<JsonDocument> SelectAsJson(IWhereClause? filter) +    { +        return Select(filter).Select(e => _jsonHelper.ConvertEntityToJson(e)).ToList(); +    } + +    public JsonDocument SelectAsJsonByKey(object key) +    { +        return SelectAsJson(WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key)).Single(); +    } + +    public object InsertFromJson(JsonDocument? json) +    { +        // TODO: Implement this. +        throw new NotImplementedException(); +    }  } diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs index 3467625..46b2e5b 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs @@ -2,10 +2,20 @@ namespace CrupestApi.Commons.Crud;  public static class CrudWebApplicationExtensions  { -    public static WebApplication UseCrud(this WebApplication app, string path) +    public static WebApplication UseCrud<TEntity>(this WebApplication app, string path) where TEntity : class      {          app.MapGet(path, async (context) =>          { +            var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>(); + +            var result = crudService.SelectAsJson(null); + +            await context.ResponseJsonAsync(result); +        }); + +        app.MapPost(path, async (context) => +        { +            var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();          }); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs new file mode 100644 index 0000000..a1e4583 --- /dev/null +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs @@ -0,0 +1,36 @@ +using System.Text.Json; + +namespace CrupestApi.Commons.Crud; + +public class EntityJsonHelper +{ +    private readonly TableInfo _table; + +    public EntityJsonHelper(TableInfo table) +    { +        _table = table; +    } + +    public virtual JsonDocument ConvertEntityToJson(object? entity) +    { +        if (entity is null) return JsonSerializer.SerializeToDocument<object?>(null); + +        var result = new Dictionary<string, object?>(); + +        foreach (var column in _table.ColumnInfos) +        { +            if (column.PropertyInfo is not null) +            { +                result.Add(column.ColumnName, column.PropertyInfo.GetValue(entity)); +            } +        } + +        return JsonSerializer.SerializeToDocument(result); +    } + +    public virtual object? ConvertJsonToEntity(JsonDocument? json) +    { +        // TODO: Implement this. +        throw new NotImplementedException(); +    } +} diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs index 5bb19ad..498529c 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs @@ -27,8 +27,9 @@ public class TableInfo          var columnInfos = new List<ColumnInfo>(); -        bool hasPrimaryKey = false;          bool hasId = false; +        ColumnInfo? primaryKeyColumn = null; +        ColumnInfo? keyColumn = null;          List<PropertyInfo> columnProperties = new();          List<PropertyInfo> nonColumnProperties = new(); @@ -40,11 +41,21 @@ public class TableInfo                  var columnInfo = new ColumnInfo(this, property, _columnTypeProvider);                  columnInfos.Add(columnInfo);                  if (columnInfo.IsPrimaryKey) -                    hasPrimaryKey = true; +                { +                    primaryKeyColumn = columnInfo; +                }                  if (columnInfo.ColumnName.Equals("id", StringComparison.OrdinalIgnoreCase))                  {                      hasId = true;                  } +                if (columnInfo.IsSpecifiedAsKey) +                { +                    if (keyColumn is not null) +                    { +                        throw new Exception("Already exists a key column."); +                    } +                    keyColumn = columnInfo; +                }                  columnProperties.Add(property);              }              else @@ -53,14 +64,21 @@ public class TableInfo              }          } -        if (!hasPrimaryKey) +        if (primaryKeyColumn is null)          {              if (hasId) throw new Exception("A column named id already exists but is not primary key."); -            var columnInfo = CreateAutoIdColumn(); -            columnInfos.Add(columnInfo); +            primaryKeyColumn = CreateAutoIdColumn(); +            columnInfos.Add(primaryKeyColumn); +        } + +        if (keyColumn is null) +        { +            keyColumn = primaryKeyColumn;          }          ColumnInfos = columnInfos; +        PrimaryKeyColumn = primaryKeyColumn; +        KeyColumn = keyColumn;          ColumnProperties = columnProperties;          NonColumnProperties = nonColumnProperties; @@ -85,6 +103,12 @@ public class TableInfo      public Type EntityType { get; }      public string TableName { get; }      public IReadOnlyList<ColumnInfo> ColumnInfos { get; } +    public ColumnInfo PrimaryKeyColumn { get; } +    /// <summary> +    /// Maybe not the primary key. But acts as primary key. +    /// </summary> +    /// <seealso cref="ColumnMetadataKeys.ActAsKey"/> +    public ColumnInfo KeyColumn { get; }      public IReadOnlyList<PropertyInfo> ColumnProperties { get; }      public IReadOnlyList<PropertyInfo> NonColumnProperties { get; }      public IReadOnlyList<string> ColumnNameList => _lazyColumnNameList.Value; @@ -412,10 +436,10 @@ CREATE TABLE {tableName}(          });      } -    public virtual int Insert(IDbConnection dbConnection, IInsertClause insert) +    // Returns the insert entity's key. +    public object Insert(IDbConnection dbConnection, IInsertClause insert)      { -        var (sql, parameters) = GenerateInsertSql(insert); - +        object? key = null;          foreach (var column in ColumnInfos)          {              InsertItem? item = insert.Items.FirstOrDefault(i => i.ColumnName == column.ColumnName); @@ -423,16 +447,25 @@ CREATE TABLE {tableName}(              column.Hooks.BeforeInsert(column, ref value);              if (item is null)              { -                if (value is not null) -                    insert.Items.Add(new InsertItem(column.ColumnName, value)); +                item = new InsertItem(column.ColumnName, value); +                insert.Items.Add(item);              }              else              {                  item.Value = value;              } + +            if (item.ColumnName == KeyColumn.ColumnName) +            { +                key = item.Value; +            }          } -        return dbConnection.Execute(sql, ConvertParameters(parameters)); +        var (sql, parameters) = GenerateInsertSql(insert); + +        dbConnection.Execute(sql, ConvertParameters(parameters)); + +        return key ?? throw new Exception("No key???");      }      public virtual int Update(IDbConnection dbConnection, IWhereClause? where, IUpdateClause update) diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs index 768a6d2..9023f4e 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/HttpResponseAction.cs @@ -1,4 +1,3 @@  namespace CrupestApi.Commons;  public delegate void HttpResponseAction(HttpResponse response); -public delegate Task AsyncHttpResponseAction(HttpResponse response); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs index 4f5862f..8c4b34d 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs @@ -46,35 +46,38 @@ public static class CrupestApiJsonExtensions          return services;      } -    public static async Task WriteJsonAsync<T>(this HttpResponse response, T bodyObject, int statusCode, HttpResponseAction? beforeWriteBody, CancellationToken cancellationToken = default) -    { -        await response.WriteJsonAsync(bodyObject, statusCode, (context) => -        { -            beforeWriteBody?.Invoke(context); -            return Task.CompletedTask; -        }, cancellationToken); -    } - -    public static async Task WriteJsonAsync<T>(this HttpResponse response, T bodyObject, int statusCode = 200, AsyncHttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) +    public static async Task WriteJsonAsync<T>(this HttpResponse response, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default)      {          var jsonOptions = response.HttpContext.RequestServices.GetRequiredService<IOptionsSnapshot<JsonSerializerOptions>>();          byte[] json = JsonSerializer.SerializeToUtf8Bytes<T>(bodyObject, jsonOptions.Value);          var byteCount = json.Length; +          response.StatusCode = statusCode;          response.Headers.ContentType = "application/json; charset=utf-8";          response.Headers.ContentLength = byteCount;          if (beforeWriteBody is not null)          { -            await beforeWriteBody(response); +            beforeWriteBody(response);          }          await response.Body.WriteAsync(json, cancellationToken);      } -    public static async Task WriteMessageAsync(this HttpResponse response, string message, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) +    public static async Task WriteMessageAsync(this HttpResponse response, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default)      {          await response.WriteJsonAsync(new ErrorBody(message), statusCode: statusCode, beforeWriteBody, cancellationToken);      } + +    public static Task ResponseJsonAsync<T>(this HttpContext context, T bodyObject, int statusCode = 200, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) +    { +        return context.Response.WriteJsonAsync<T>(bodyObject, statusCode, beforeWriteBody, cancellationToken); +    } + +    public static Task ResponseMessageAsync<T>(this HttpContext context, string message, int statusCode = 400, HttpResponseAction? beforeWriteBody = null, CancellationToken cancellationToken = default) +    { +        return context.Response.WriteMessageAsync(message, statusCode, beforeWriteBody, cancellationToken); +    } +  }  | 
