aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-12-13 17:17:06 +0800
committercrupest <crupest@outlook.com>2022-12-20 20:32:53 +0800
commit799170d34c8b59116895f07328412c4b2236b39e (patch)
tree58bcafc3383e26943f3b8d86136d707c24b25c8b
parent90aca5d4ca4aabdf7b1bfcbca1ddf1305bd2afab (diff)
downloadcrupest-799170d34c8b59116895f07328412c4b2236b39e.tar.gz
crupest-799170d34c8b59116895f07328412c4b2236b39e.tar.bz2
crupest-799170d34c8b59116895f07328412c4b2236b39e.zip
Develop secret api. v37
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs2
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs89
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md27
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs27
4 files changed, 68 insertions, 77 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
index e91c777..aa3e4f8 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
@@ -50,7 +50,7 @@ public class ColumnInfo
public bool IsNotNull => IsPrimaryKey || Metadata.GetValueOrDefault(ColumnMetadataKeys.NotNull) is true;
public bool IsGenerated => Metadata.GetValueOrDefault(ColumnMetadataKeys.Generated) is true;
public bool IsNoUpdate => Metadata.GetValueOrDefault(ColumnMetadataKeys.NoUpdate) is true;
- public bool CanBeGenerated => (bool?)Metadata.GetValueOrDefault(ColumnMetadataKeys.CanBeGenerated) ?? (DefaultValueGeneratorMethod is not null);
+ public bool CanBeGenerated => (bool?)Metadata.GetValueOrDefault(ColumnMetadataKeys.CanBeGenerated) ?? (DefaultValueGeneratorMethod is not null || IsAutoIncrement);
/// <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>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
index 6119396..7db843b 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
@@ -12,35 +12,33 @@ namespace CrupestApi.Commons.Crud;
public class EntityJsonHelper<TEntity> where TEntity : class
{
private readonly TableInfo _table;
- private readonly JsonSerializerOptions _jsonSerializerOptions;
+ private readonly IOptionsMonitor<JsonSerializerOptions> _jsonSerializerOptions;
- public EntityJsonHelper(TableInfoFactory tableInfoFactory)
+ public EntityJsonHelper(TableInfoFactory tableInfoFactory, IOptionsMonitor<JsonSerializerOptions> jsonSerializerOptions)
{
_table = tableInfoFactory.Get(typeof(TEntity));
- _jsonSerializerOptions = new JsonSerializerOptions();
- _jsonSerializerOptions.AllowTrailingCommas = true;
- _jsonSerializerOptions.PropertyNameCaseInsensitive = true;
- _jsonSerializerOptions.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
- foreach (var type in _table.Columns.Select(c => c.ColumnType))
- {
- if (type.JsonConverter is not null)
- {
- _jsonSerializerOptions.Converters.Add(type.JsonConverter);
- }
- }
+ _jsonSerializerOptions = jsonSerializerOptions;
}
- public virtual Dictionary<string, object?> ConvertEntityToDictionary(object? entity)
+ public virtual Dictionary<string, object?> ConvertEntityToDictionary(object? entity, bool includeNonColumnProperties = false)
{
Debug.Assert(entity is null || entity is TEntity);
var result = new Dictionary<string, object?>();
- foreach (var column in _table.PropertyColumns)
+ foreach (var propertyInfo in _table.ColumnProperties)
{
- var propertyInfo = column.PropertyInfo;
- var value = propertyInfo!.GetValue(entity);
- result[column.ColumnName] = value;
+ var value = propertyInfo.GetValue(entity);
+ result[propertyInfo.Name] = value;
+ }
+
+ if (includeNonColumnProperties)
+ {
+ foreach (var propertyInfo in _table.NonColumnProperties)
+ {
+ var value = propertyInfo.GetValue(entity);
+ result[propertyInfo.Name] = value;
+ }
}
return result;
@@ -51,50 +49,53 @@ public class EntityJsonHelper<TEntity> where TEntity : class
Debug.Assert(entity is null || entity is TEntity);
var dictionary = ConvertEntityToDictionary(entity);
- return JsonSerializer.Serialize(dictionary, _jsonSerializerOptions);
+ return JsonSerializer.Serialize(dictionary, _jsonSerializerOptions.CurrentValue);
}
- public virtual TEntity ConvertDictionaryToEntityForInsert(IReadOnlyDictionary<string, object?> dictionary)
+ public virtual IInsertClause ConvertJsonElementToInsertClauses(JsonElement rootElement)
{
- var result = Activator.CreateInstance<TEntity>()!;
+ var insertClause = InsertClause.Create();
+
+ if (rootElement.ValueKind != JsonValueKind.Object)
+ {
+ throw new UserException("The root element must be an object.");
+ }
foreach (var column in _table.PropertyColumns)
{
- var propertyInfo = column.PropertyInfo!;
- var value = dictionary.GetValueOrDefault(column.ColumnName);
- if (column.IsGenerated)
+ object? value = null;
+ if (rootElement.TryGetProperty(column.ColumnName, out var propertyElement))
{
- if (value is not null)
+ value = propertyElement.ValueKind switch
{
- throw new UserException($"{propertyInfo.Name} is auto generated. Don't specify it.");
- }
+ JsonValueKind.Null or JsonValueKind.Undefined => null,
+ JsonValueKind.Number => propertyElement.GetDouble(),
+ JsonValueKind.True => true,
+ JsonValueKind.False => false,
+ JsonValueKind.String => propertyElement.GetString(),
+ _ => throw new Exception($"Bad json value of property {column.ColumnName}.")
+ };
}
- if (value is null)
+ if (column.IsGenerated && value is not null)
{
- if (column.IsNotNull && !column.CanBeGenerated)
- {
- throw new UserException($"{propertyInfo.Name} can't be null.");
- }
- propertyInfo.SetValue(result, null);
+ throw new UserException($"The property {column.ColumnName} is generated. You cannot specify its value.");
}
- else
+
+ if (column.IsNotNull && !column.CanBeGenerated && value is null)
{
- // Check type
- var columnType = column.ColumnType;
- if (columnType.ClrType.IsAssignableFrom(value.GetType()))
- propertyInfo.SetValue(result, value);
- else
- throw new UserException($"{propertyInfo.Name} is of wrong type.");
+ throw new UserException($"The property {column.ColumnName} can't be null or generated. But you specify a null value.");
}
+
+ insertClause.Add(column.ColumnName, value);
}
- return result;
+ return insertClause;
}
- public TEntity ConvertJsonToEntityForInsert(string json)
+ public IInsertClause ConvertJsonToEntityForInsert(string json)
{
- var dictionary = JsonSerializer.Deserialize<Dictionary<string, object?>>(json, _jsonSerializerOptions)!;
- return ConvertDictionaryToEntityForInsert(dictionary);
+ var document = JsonSerializer.Deserialize<JsonDocument>(json, _jsonSerializerOptions.CurrentValue)!;
+ return ConvertJsonElementToInsertClauses(document.RootElement);
}
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md
index ca8a6f1..b008ea7 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/README.md
@@ -19,24 +19,29 @@ The ultimate CRUD scaffold finally comes.
1. Create insert clause.
2. Check clauses' related columns are valid.
-3. For each column:
+3. Create a real empty insert clause.
+4. For each 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 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.
+ 3. If value is `null` and the column `IsAutoIncrement` is true, skip to next column.
+ 4. Coerce null to `DbNullValue`.
+ 5. Run validator to validate the value.
+ 6. If value is `DbNullValue`, `IsNotNull` is true, throw exception.
+ 7. Add column and value to real insert clause.
+5. Generate sql string and param list.
+6. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`.
+7. Execute sql and return `KeyColumn` value.
### Update
1. Create update clause, where clause.
2. Check clauses' related columns are valid. Then generate sql string and param list.
-3. For each column:
+3. Create a real empty update clause.
+4. For each column:
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.
+ 4. Add column and value to real update clause.
+5. Generate sql string and param list.
+6. Convert param list to `Dapper` dynamic params with proper type conversion in `IColumnTypeInfo`.
+7. 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 869e987..b552e6b 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
@@ -285,25 +285,6 @@ CREATE TABLE {tableName}(
return (result.ToString(), parameters);
}
- public void CheckInsertClause(IInsertClause insertClause)
- {
- var columnNameSet = new HashSet<string>(Columns.Select(c => c.ColumnName));
-
- foreach (var item in insertClause.Items)
- {
- columnNameSet.Remove(item.ColumnName);
- }
-
- foreach (var columnName in columnNameSet)
- {
- var column = GetColumn(columnName);
- if (!column.IsAutoIncrement)
- {
- throw new Exception($"Column {columnName} is not specified and is not auto increment.");
- }
- }
- }
-
/// <summary>
/// If you call this manually, it's your duty to call hooks.
/// </summary>
@@ -311,7 +292,6 @@ CREATE TABLE {tableName}(
public (string sql, ParamList parameters) GenerateInsertSql(IInsertClause insertClause, string? dbProviderId = null)
{
CheckRelatedColumns(insertClause);
- CheckInsertClause(insertClause);
var parameters = new ParamList();
@@ -484,6 +464,11 @@ CREATE TABLE {tableName}(
value = column.InvokeDefaultValueGenerator();
}
+ if (value is null && column.IsAutoIncrement)
+ {
+ continue;
+ }
+
if (value is null)
{
value = DbNullValue.Instance;
@@ -493,7 +478,7 @@ CREATE TABLE {tableName}(
if (value is DbNullValue)
{
- if (column.IsNotNull && !column.IsAutoIncrement)
+ if (column.IsNotNull)
{
throw new Exception($"Column '{column.ColumnName}' is not nullable. Please specify a non-null value.");
}