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 | 90aca5d4ca4aabdf7b1bfcbca1ddf1305bd2afab (patch) | |
tree | b646eaa164b4b2fc5f712ceddbb92b2b67865295 /docker | |
parent | 72f0786810ec3afc7a7e42fdeb392717eeb1055b (diff) | |
download | crupest-90aca5d4ca4aabdf7b1bfcbca1ddf1305bd2afab.tar.gz crupest-90aca5d4ca4aabdf7b1bfcbca1ddf1305bd2afab.tar.bz2 crupest-90aca5d4ca4aabdf7b1bfcbca1ddf1305bd2afab.zip |
Develop secret api. v36
Diffstat (limited to 'docker')
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); } } |