aboutsummaryrefslogtreecommitdiff
path: root/docker/crupest-api/CrupestApi/CrupestApi.Commons
diff options
context:
space:
mode:
Diffstat (limited to 'docker/crupest-api/CrupestApi/CrupestApi.Commons')
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs41
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs3
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs58
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs16
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs70
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs5
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs5
7 files changed, 185 insertions, 13 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
index c3d118c..1329c99 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnInfo.cs
@@ -1,8 +1,12 @@
+using System.Data;
using System.Reflection;
using System.Text;
namespace CrupestApi.Commons.Crud;
+public delegate Task EntityPreSave(object? entity, ColumnInfo column, TableInfo table, IDbConnection connection);
+public delegate Task EntityPostGet(object? entity, ColumnInfo column, TableInfo table, IDbConnection connection);
+
public class ColumnInfo
{
private Type ExtractRealTypeFromNullable(Type type)
@@ -24,7 +28,7 @@ public class ColumnInfo
}
EntityType = entityType;
- PropertyName = null;
+ PropertyName = sqlColumnName;
PropertyType = typeof(int);
PropertyRealType = typeof(int);
SqlColumnName = sqlColumnName;
@@ -45,36 +49,55 @@ public class ColumnInfo
EntityType = entityType;
PropertyName = entityPropertyName;
+ PropertyInfo = entityType.GetProperty(entityPropertyName);
- var property = entityType.GetProperty(entityPropertyName);
-
- if (property is null)
+ if (PropertyInfo is null)
throw new Exception("Public property with given name does not exist.");
- PropertyType = property.PropertyType;
+ PropertyType = PropertyInfo.PropertyType;
PropertyRealType = ExtractRealTypeFromNullable(PropertyType);
- var columnAttribute = property.GetCustomAttribute<ColumnAttribute>();
+ var columnAttribute = PropertyInfo.GetCustomAttribute<ColumnAttribute>();
if (columnAttribute is null)
{
SqlColumnName = PropertyName;
Nullable = true;
IndexType = ColumnIndexType.None;
+ DefaultEmptyForString = false;
}
else
{
SqlColumnName = columnAttribute.DatabaseName ?? PropertyName;
Nullable = !columnAttribute.NonNullable;
IndexType = columnAttribute.IndexType;
+ DefaultEmptyForString = columnAttribute.DefaultEmptyForString;
}
ColumnTypeInfo = typeRegistry.GetRequiredByDataType(PropertyRealType);
TypeRegistry = typeRegistry;
+
+ if (DefaultEmptyForString)
+ {
+ EntityPostGet += (entity, column, _, _) =>
+ {
+ var pi = column.PropertyInfo;
+ if (pi is not null && column.ColumnTypeInfo.GetDatabaseType() == typeof(string))
+ {
+ var value = pi.GetValue(entity);
+ if (value is null)
+ {
+ pi.SetValue(entity, string.Empty);
+ }
+ }
+ return Task.CompletedTask;
+ };
+ }
}
public Type EntityType { get; }
// If null, there is no corresponding property.
- public string? PropertyName { get; }
+ public PropertyInfo? PropertyInfo { get; } = null;
+ public string PropertyName { get; }
public Type PropertyType { get; }
public Type PropertyRealType { get; }
public string SqlColumnName { get; }
@@ -84,6 +107,10 @@ public class ColumnInfo
public bool IsPrimaryKey { get; }
public bool IsAutoIncrement { get; }
public ColumnIndexType IndexType { get; }
+ public bool DefaultEmptyForString { get; }
+
+ public event EntityPreSave? EntityPreSave;
+ public event EntityPostGet? EntityPostGet;
public string SqlType => TypeRegistry.GetSqlType(ColumnTypeInfo);
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs
index 6f46cd5..c31a13e 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnMetadata.cs
@@ -28,4 +28,7 @@ public class ColumnAttribute : Attribute, IColumnMetadata
public bool IsAutoIncrement { get; set; }
public ColumnIndexType IndexType { get; set; } = ColumnIndexType.None;
+
+ // Use empty string for default value of string type.
+ public bool DefaultEmptyForString { get; set; }
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
index ff8ccea..d7adb33 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/ColumnTypeInfo.cs
@@ -1,9 +1,16 @@
using System.Diagnostics;
+using System.Text.Json;
+using System.Text.Json.Serialization;
namespace CrupestApi.Commons.Crud;
public interface IColumnTypeInfo
{
+ JsonConverter? GetOptionalJsonConverter()
+ {
+ return null;
+ }
+
Type GetDataType();
Type GetDatabaseType();
object ConvertToDatabase(object data);
@@ -122,6 +129,46 @@ public abstract class CustomColumnTypeInfo<TDataType, TDatabaseType> : ICustomCo
}
}
+public class DateTimeColumnTypeInfo : CustomColumnTypeInfo<DateTime, long>
+{
+ private readonly DateTimeJsonConverter _jsonConverter = new DateTimeJsonConverter();
+
+ public JsonConverter GetJsonConverter()
+ {
+ return _jsonConverter;
+ }
+
+ public override long ConvertToDatabase(DateTime data)
+ {
+ return new DateTimeOffset(data).ToUnixTimeSeconds();
+ }
+
+ public override DateTime ConvertFromDatabase(long databaseData)
+ {
+ return DateTimeOffset.FromUnixTimeSeconds(databaseData).LocalDateTime;
+ }
+}
+
+public class DateTimeJsonConverter : JsonConverter<DateTime>
+{
+ public override bool HandleNull => false;
+
+ public override bool CanConvert(Type typeToConvert)
+ {
+ return typeToConvert == typeof(DateTime);
+ }
+
+ public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
+ {
+ return DateTimeOffset.FromUnixTimeSeconds(reader.GetInt64()).LocalDateTime;
+ }
+
+ public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
+ {
+ writer.WriteNumberValue(new DateTimeOffset(value).ToUnixTimeSeconds());
+ }
+}
+
public class ColumnTypeInfoRegistry
{
public static IReadOnlyList<IColumnTypeInfo> BuiltinList = new List<IColumnTypeInfo>()
@@ -139,7 +186,7 @@ public class ColumnTypeInfoRegistry
public static IReadOnlyList<IColumnTypeInfo> CustomList = new List<IColumnTypeInfo>()
{
- // TODO: Add custom ones.
+ new DateTimeColumnTypeInfo(),
};
public static ColumnTypeInfoRegistry Singleton { get; }
@@ -229,4 +276,13 @@ public class ColumnTypeInfoRegistry
}
}
+ public IEnumerable<JsonConverter> GetJsonConverters()
+ {
+ foreach (var columnTypeInfo in _list)
+ {
+ var converter = columnTypeInfo.GetOptionalJsonConverter();
+ if (converter is not null)
+ yield return converter;
+ }
+ }
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
index bbd5e9a..7da6ac7 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
@@ -8,13 +8,13 @@ public class CrudService<TEntity>
{
protected readonly TableInfo _table;
protected readonly IOptionsSnapshot<CrupestApiConfig> _crupestApiOptions;
- protected readonly ILogger<CrudService<TEntity>> _logger;
+ private readonly ILogger<CrudService<TEntity>> _logger;
- public CrudService(IOptionsSnapshot<CrupestApiConfig> crupestApiOptions, ILogger<CrudService<TEntity>> logger)
+ public CrudService(ServiceProvider services)
{
_table = new TableInfo(typeof(TEntity));
- _crupestApiOptions = crupestApiOptions;
- _logger = logger;
+ _crupestApiOptions = services.GetRequiredService<IOptionsSnapshot<CrupestApiConfig>>();
+ _logger = services.GetRequiredService<ILogger<CrudService<TEntity>>>();
}
public virtual string GetDbConnectionString()
@@ -78,4 +78,12 @@ public class CrudService<TEntity>
var sql = _table.GenerateUpdateSql(where, update, out parameters);
return await connection.ExecuteAsync(sql, parameters);
}
+
+ public virtual async Task<int> DeleteAsync(WhereClause? where)
+ {
+ var connection = await EnsureDatabase();
+ DynamicParameters parameters;
+ var sql = _table.GenerateDeleteSql(where, out parameters);
+ return await connection.ExecuteAsync(sql, parameters);
+ }
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
index 9610e40..c58897c 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/TableInfo.cs
@@ -190,6 +190,46 @@ CREATE TABLE {tableName}(
return result.ToString();
}
+ public InsertClause GenerateInsertClauseFromObject(object value)
+ {
+ var insertClause = InsertClause.Create();
+
+ foreach (var column in ColumnInfos)
+ {
+ var propertyInfo = column.PropertyInfo;
+ if (propertyInfo is null)
+ {
+ propertyInfo = EntityType.GetProperty(column.PropertyName);
+ }
+ if (propertyInfo is null)
+ {
+ if (column.IsAutoIncrement)
+ {
+ continue;
+ }
+ else
+ {
+ throw new Exception($"Property {column.PropertyName} not found.");
+ }
+ }
+
+ var propertyValue = propertyInfo.GetValue(value);
+ if (propertyValue is null)
+ {
+ if (column.IsAutoIncrement)
+ {
+ continue;
+ }
+ else
+ {
+ insertClause.Add(column.SqlColumnName, propertyValue);
+ }
+ }
+ }
+
+ return insertClause;
+ }
+
public string GenerateInsertSql(InsertClause insertClause, out DynamicParameters parameters)
{
var relatedColumns = insertClause.GetRelatedColumns();
@@ -244,4 +284,32 @@ CREATE TABLE {tableName}(
return sb.ToString();
}
-} \ No newline at end of file
+
+ public string GenerateDeleteSql(WhereClause? whereClause, out DynamicParameters parameters)
+ {
+ if (whereClause is not null)
+ {
+ var relatedColumns = ((IWhereClause)whereClause).GetRelatedColumns() ?? new List<string>();
+ foreach (var column in relatedColumns)
+ {
+ if (!ColumnNameList.Contains(column))
+ {
+ throw new ArgumentException($"Column {column} is not in the table.");
+ }
+ }
+ }
+
+ parameters = new DynamicParameters();
+
+ StringBuilder sb = new StringBuilder("DELETE FROM ");
+ sb.Append(TableName);
+ if (whereClause is not null)
+ {
+ sb.Append(" WHERE ");
+ sb.Append(whereClause.GenerateSql(parameters));
+ }
+ sb.Append(';');
+
+ return sb.ToString();
+ }
+}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
index 674ac9d..2352e7e 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/WhereClause.cs
@@ -213,6 +213,11 @@ public class WhereClause : IWhereClause
return new WhereClause(clauses);
}
+ public WhereClause Add(string column, string op, object value)
+ {
+ return Add(CompareWhereClause.Create(column, op, value));
+ }
+
public WhereClause Eq(string column, object value)
{
return Add(CompareWhereClause.Eq(column, value));
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
index 1d8106c..bbb6efe 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Json.cs
@@ -1,4 +1,5 @@
using System.Text.Json;
+using CrupestApi.Commons.Crud;
using Microsoft.Extensions.Options;
namespace CrupestApi.Commons;
@@ -13,6 +14,10 @@ public static class CrupestApiJsonExtensions
config.AllowTrailingCommas = true;
config.PropertyNameCaseInsensitive = true;
config.PropertyNamingPolicy = JsonNamingPolicy.CamelCase;
+ foreach (var converter in ColumnTypeInfoRegistry.Singleton.GetJsonConverters())
+ {
+ config.Converters.Add(converter);
+ }
});
return services;