diff options
| author | crupest <crupest@outlook.com> | 2022-12-13 16:44:25 +0800 | 
|---|---|---|
| committer | crupest <crupest@outlook.com> | 2022-12-20 20:32:53 +0800 | 
| commit | 37ccef55ad134cc10e91d82fe6b60286daf644cc (patch) | |
| tree | b646eaa164b4b2fc5f712ceddbb92b2b67865295 /docker/crupest-api | |
| parent | 9a2e48b64befc039b71ec6fff9b58060ca1d1268 (diff) | |
| download | crupest-37ccef55ad134cc10e91d82fe6b60286daf644cc.tar.gz crupest-37ccef55ad134cc10e91d82fe6b60286daf644cc.tar.bz2 crupest-37ccef55ad134cc10e91d82fe6b60286daf644cc.zip  | |
Develop secret api. v36
Diffstat (limited to 'docker/crupest-api')
3 files changed, 52 insertions, 194 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs index 0ac6e7b..e91c777 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs @@ -4,62 +4,6 @@ using System.Text;  namespace CrupestApi.Commons.Crud; -public class ColumnHooks -{ -    // value: -    //   null => not specified -    //   DbNullValue => specified as NULL -    //   other => specified as value -    public delegate void ColumnHookAction(ColumnInfo column, ref object? value); - -    public ColumnHooks(ColumnHookAction afterSelect, ColumnHookAction beforeInsert, ColumnHookAction beforeUpdate) -    { -        AfterSelect = afterSelect; -        BeforeInsert = beforeInsert; -        BeforeUpdate = beforeUpdate; -    } - -    /// <summary>Called after SELECT. Please use multicast if you want to customize it because there are many default behavior in it.</summary> -    /// <remarks> -    /// Called after column type transformation. -    /// value(in): -    ///     null => not found in SELECT result -    ///     DbNullValue => database NULL -    ///     others => database value -    /// value(out): -    ///     null/DbNullValue => return null -    ///     others => return as is -    /// </remarks> -    public ColumnHookAction AfterSelect; - -    /// <summary>Called before INSERT. Please use multicast if you want to customize it because there are many default behavior in it.</summary> -    /// <remarks> -    /// Called before column type transformation. -    /// value(in): -    ///     null => not specified by insert clause -    ///     DbNullValue => specified as database NULL -    ///     other => specified as other value -    /// value(out): -    ///     null/DbNullValue => save database NULL -    ///     other => save the value as is -    /// </remarks> -    public ColumnHookAction BeforeInsert; - -    /// <summary>Called before UPDATE. Please use multicast if you want to customize it because there are many default behavior in it.</summary  -    /// <remarks> -    /// Called before column type transformation. -    /// value(in): -    ///     null => not specified by update clause -    ///     DbNullValue => specified as database NULL -    ///     other => specified as other value -    /// value(out): -    ///     null => not update -    ///     DbNullValue => update to database NULL -    ///     other => update to the value -    /// </remarks> -    public ColumnHookAction BeforeUpdate; -} -  public class ColumnInfo  {      private readonly AggregateColumnMetadata _metadata = new AggregateColumnMetadata(); @@ -72,12 +16,6 @@ public class ColumnInfo          Table = table;          _metadata.Add(metadata);          ColumnType = typeProvider.Get(clrType); - -        Hooks = new ColumnHooks( -            new ColumnHooks.ColumnHookAction(OnAfterSelect), -            new ColumnHooks.ColumnHookAction(OnBeforeInsert), -            new ColumnHooks.ColumnHookAction(OnBeforeUpdate) -        );      }      /// <summary> @@ -94,16 +32,12 @@ public class ColumnInfo          {              _metadata.Add(columnAttribute);          } - -        Hooks = new ColumnHooks( -            new ColumnHooks.ColumnHookAction(OnAfterSelect), -            new ColumnHooks.ColumnHookAction(OnBeforeInsert), -            new ColumnHooks.ColumnHookAction(OnBeforeUpdate) -        );      }      public TableInfo Table { get; } +    public Type EntityType => Table.EntityType; +      // If null, there is no corresponding property.      public PropertyInfo? PropertyInfo { get; } = null; @@ -111,8 +45,6 @@ public class ColumnInfo      public IColumnTypeInfo ColumnType { get; } -    public ColumnHooks Hooks { get; } -      public bool IsPrimaryKey => Metadata.GetValueOrDefault(ColumnMetadataKeys.IsPrimaryKey) is true;      public bool IsAutoIncrement => Metadata.GetValueOrDefault(ColumnMetadataKeys.IsAutoIncrement) is true;      public bool IsNotNull => IsPrimaryKey || Metadata.GetValueOrDefault(ColumnMetadataKeys.NotNull) is true; @@ -163,35 +95,31 @@ public class ColumnInfo          }      } -    public MethodInfo ValidatorMethod +    public MethodInfo? ValidatorMethod      {          get          { -            object? value = Metadata.GetValueOrDefault(ColumnMetadataKeys.Validator); +            object? value = Metadata.GetValueOrDefault(ColumnMetadataKeys.DefaultValueGenerator);              Debug.Assert(value is null || value is string); +            MethodInfo? result;              if (value is null)              { -                return GetType().GetMethod(nameof(DefaultValidator))!; +                string methodName = ColumnName + "Validator"; +                result = Table.EntityType.GetMethod(methodName, BindingFlags.Static);              }              else              {                  string methodName = (string)value; -                return Table.EntityType.GetMethod(methodName, BindingFlags.Static) ?? throw new Exception("The validator does not exist."); +                result = Table.EntityType.GetMethod(methodName, BindingFlags.Static) ?? throw new Exception("The validator does not exist.");              } + +            return result;          }      }      public void InvokeValidator(object value)      { -        ValidatorMethod.Invoke(null, new object?[] { this, value }); -    } - -    public static void DefaultValidator(ColumnInfo column, object value) -    { -        if (column.IsNotNull && value is DbNullValue) -        { -            throw new Exception("The column can't be null."); -        } +        ValidatorMethod?.Invoke(null, new object?[] { this, value });      }      public object? InvokeDefaultValueGenerator() @@ -199,37 +127,6 @@ public class ColumnInfo          return DefaultValueGeneratorMethod?.Invoke(null, new object?[] { this });      } -    public static object? DefaultDefaultValueGenerator(ColumnInfo column) -    { -        return DbNullValue.Instance; -    } - -    private void TryCoerceStringFromNullToEmpty(ref object? value) -    { -        if (ColumnType.ClrType == typeof(string) && (Metadata.GetValueOrDefault<bool?>(ColumnMetadataKeys.DefaultEmptyForString) is true) && value is DbNullValue) -        { -            value = ""; -        } -    } - -    protected void OnAfterSelect(ColumnInfo column, ref object? value) -    { -        TryCoerceStringFromNullToEmpty(ref value); -    } - -    protected void OnBeforeInsert(ColumnInfo column, ref object? value) -    { -        TryCoerceStringFromNullToEmpty(ref value); -    } - -    protected void OnBeforeUpdate(ColumnInfo column, ref object? value) -    { -        if (IsNoUpdate && value is not null) -            throw new Exception("The column can't be updated."); - -        TryCoerceStringFromNullToEmpty(ref value); -    } -      public string GenerateCreateTableColumnString(string? dbProviderId = null)      {          StringBuilder result = new StringBuilder(); diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md index 22289cb..ca8a6f1 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md @@ -9,34 +9,34 @@ The ultimate CRUD scaffold finally comes.  ### Select  1. Create select `what`, where clause, order clause, `Offset` and `Limit`. -2. Check clauses' related columns are valid. Then generate sql string and param list. -3. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. Execute sql and get `dynamic`s. -4. For each column: -    1. If column not in query result is null, null will be used to call hooks. -    2. If column is `NULL`, `DbNullValue` will be used to call hooks. -    3. Otherwise run conversion in `IColumnTypeInfo`. -    4. Run hook `AfterSelect` for every column. -5. Convert `dynamic`s to `TEntity`s. +2. Check clauses' related columns are valid. +3. Generate sql string and param list. +4. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. +5. Execute sql and get `dynamic`s. +6. (Optional) Convert `dynamic`s to `TEntity`s.  ### Insert -1. Create insert clause consisting of insert items. -2. Check clauses' related columns are valid. Then generate sql string and param list. +1. Create insert clause. +2. Check clauses' related columns are valid.  3. For each column: -    1. If insert item exits and value is not null but the column `IsGenerated` is true, throw exception. -    2. If insert item does not exist or value is `null` for that column, use default value generator to generate value. However, `DbNullValue` always means use `NULL` for that column. +    1. If insert item exists and value is not null but the column `IsGenerated` is true, throw exception. +    2. If insert item does not exist or value is `null`, use default value generator to generate value. However, `DbNullValue` always means use `NULL` for that column.      3. Coerce null to `DbNullValue`. -    4. Run hook `BeforeInsert`. -    5. Coerce null to `DbNullValue`. -    6. Run validator. -4. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. Execute sql and return `KeyColumn` value. +    4. Run validator to validate the value. +    5. If value is `DbNullValue`, `IsNotNull` is true and `IsAutoIncrement` is false, throw exception. +4. Generate sql string and param list. +5. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. +6. Execute sql and return `KeyColumn` value.  ### Update -1. Create update clause consisted of update items, where clause. +1. Create update clause, where clause.  2. Check clauses' related columns are valid. Then generate sql string and param list.  3. For each column: -    1. If insert item does not exist, `null` will be used to call hooks. However, `DbNullValue` always means use `NULL` for that column. -    2. Run hook `BeforeInsert`. If value is null, it means do not update this column. -    3. Run validator if `value` is not null. -4. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. Execute sql and get count of affected rows. +    1. If update item exists and value is not null but the column `IsNoUpdate` is true, throw exception. +    2. Invoke validator to validate the value. +    3. If `IsNotNull` is true and value is `DbNullValue`, throw exception. +4. Generate sql string and param list. +5. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`. +6. Execute sql and return count of affected rows. diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs index 15b6320..869e987 100644 --- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs +++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs @@ -417,38 +417,7 @@ CREATE TABLE {tableName}(      {          var (sql, parameters) = GenerateSelectSql(what, where, orderBy, skip, limit);          var queryResult = dbConnection.Query<dynamic>(sql, ConvertParameters(parameters)); -        return queryResult.Select(d => -        { -            Type dynamicType = d.GetType(); -            foreach (var column in Columns) -            { -                object? value = null; -                var dynamicProperty = dynamicType.GetProperty(column.ColumnName); -                if (dynamicProperty is null) -                { -                    column.Hooks.AfterSelect(column, ref value); -                } -                else -                { -                    value = dynamicProperty.GetValue(d); -                    if (value is null) -                        value = DbNullValue.Instance; -                    else -                        value = column.ColumnType.ConvertFromDatabase(value); -                    column.Hooks.AfterSelect(column, ref value); -                } - -                if (dynamicProperty is not null) -                { -                    if (value is null || value is DbNullValue) -                        dynamicProperty.SetValue(d, null); -                    else -                        dynamicProperty.SetValue(d, value); -                } -            } - -            return d; -        }).ToList(); +        return queryResult.ToList();      }      public virtual int SelectCount(IDbConnection dbConnection, IWhereClause? where = null, IOrderByClause? orderBy = null, int? skip = null, int? limit = null) @@ -502,19 +471,12 @@ CREATE TABLE {tableName}(          foreach (var column in Columns)          {              InsertItem? item = insert.Items.SingleOrDefault(i => i.ColumnName == column.ColumnName); -            object? value; -            if (item is null || item.Value is null) -            { -                value = null; -            } -            else -            { -                value = item.Value; -            } + +            var value = item?.Value;              if (column.IsGenerated && value is not null)              { -                throw new Exception("The column is generated. You can't specify it explicitly."); +                throw new Exception($"The column '{column.ColumnName}' is auto generated. You can't specify it explicitly.");              }              if (value is null) @@ -527,17 +489,21 @@ CREATE TABLE {tableName}(                  value = DbNullValue.Instance;              } -            column.Hooks.BeforeInsert(column, ref value); - -            if (value is null) -                value = DbNullValue.Instance; -              column.InvokeValidator(value);              if (value is DbNullValue) +            { +                if (column.IsNotNull && !column.IsAutoIncrement) +                { +                    throw new Exception($"Column '{column.ColumnName}' is not nullable. Please specify a non-null value."); +                } +                  realInsert.Add(column.ColumnName, null); +            }              else +            {                  realInsert.Add(column.ColumnName, value); +            }              if (item?.ColumnName == KeyColumn.ColumnName) @@ -564,22 +530,17 @@ CREATE TABLE {tableName}(          foreach (var column in Columns)          {              UpdateItem? item = update.Items.FirstOrDefault(i => i.ColumnName == column.ColumnName); - -            object? value; -            if (item is null) -            { -                value = null; -            } -            else -            { -                value = item.Value ?? DbNullValue.Instance; -            } - -            column.Hooks.BeforeUpdate(column, ref value); +            object? value = item?.Value;              if (value is not null)              { +                if (column.IsNoUpdate) +                { +                    throw new Exception($"The column '{column.ColumnName}' can't be update."); +                } +                  column.InvokeValidator(value); +                  realUpdate.Add(column.ColumnName, value);              }          }  | 
