aboutsummaryrefslogtreecommitdiff
path: root/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2022-12-21 11:51:25 +0800
committercrupest <crupest@outlook.com>2022-12-21 11:51:25 +0800
commit13a1aef3364c3ecfed41d30ceebdcd255ae8141c (patch)
tree411350f425f767fe6a8b3d1f753c713ea2b0a0e6 /docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud
parent4264d8135c066081dbabb412db17bf537ceab86e (diff)
downloadcrupest-13a1aef3364c3ecfed41d30ceebdcd255ae8141c.tar.gz
crupest-13a1aef3364c3ecfed41d30ceebdcd255ae8141c.tar.bz2
crupest-13a1aef3364c3ecfed41d30ceebdcd255ae8141c.zip
Develop secret api. v51
Diffstat (limited to 'docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud')
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs39
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs20
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/DbConnectionFactory.cs41
-rw-r--r--docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs124
4 files changed, 112 insertions, 112 deletions
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
index 1a2a055..33ff2ed 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudService.cs
@@ -1,23 +1,29 @@
using System.Data;
-using System.Text.Json;
using Dapper;
namespace CrupestApi.Commons.Crud;
+[Flags]
+public enum UpdateBehavior
+{
+ None = 0,
+ SaveNull = 1
+}
+
public class CrudService<TEntity> : IDisposable where TEntity : class
{
protected readonly TableInfo _table;
protected readonly string? _connectionName;
protected readonly IDbConnection _dbConnection;
- protected readonly EntityJsonHelper<TEntity> _jsonHelper;
+ private readonly bool _shouldDisposeConnection;
private readonly ILogger<CrudService<TEntity>> _logger;
- public CrudService(ITableInfoFactory tableInfoFactory, IDbConnectionFactory dbConnectionFactory, EntityJsonHelper<TEntity> jsonHelper, ILoggerFactory loggerFactory)
+ public CrudService(ITableInfoFactory tableInfoFactory, IDbConnectionFactory dbConnectionFactory, ILoggerFactory loggerFactory)
{
_connectionName = GetConnectionName();
_table = tableInfoFactory.Get(typeof(TEntity));
_dbConnection = dbConnectionFactory.Get(_connectionName);
- _jsonHelper = jsonHelper;
+ _shouldDisposeConnection = dbConnectionFactory.ShouldDisposeConnection;
_logger = loggerFactory.CreateLogger<CrudService<TEntity>>();
CheckDatabase(_dbConnection);
@@ -28,8 +34,6 @@ public class CrudService<TEntity> : IDisposable where TEntity : class
return typeof(TEntity).Name;
}
- public EntityJsonHelper<TEntity> JsonHelper => _jsonHelper;
-
protected virtual void CheckDatabase(IDbConnection dbConnection)
{
if (!_table.CheckExistence(dbConnection))
@@ -47,7 +51,8 @@ public class CrudService<TEntity> : IDisposable where TEntity : class
public void Dispose()
{
- _dbConnection.Dispose();
+ if (_shouldDisposeConnection)
+ _dbConnection.Dispose();
}
public List<TEntity> GetAll()
@@ -80,17 +85,23 @@ public class CrudService<TEntity> : IDisposable where TEntity : class
return (string)key;
}
- public string Create(JsonElement jsonElement)
+ public IUpdateClause ConvertEntityToUpdateClauses(TEntity entity, UpdateBehavior behavior)
{
- var insertClauses = _jsonHelper.ConvertJsonElementToInsertClauses(jsonElement);
- var key = _table.Insert(_dbConnection, insertClauses);
- return (string)key;
+ var result = UpdateClause.Create();
+ var saveNull = behavior.HasFlag(UpdateBehavior.SaveNull);
+ foreach (var column in _table.PropertyColumns)
+ {
+ var value = column.PropertyInfo!.GetValue(entity);
+ if (!saveNull && value is null) continue;
+ result.Add(column.ColumnName, value);
+ }
+ return result;
}
- public void UpdateByKey(object key, JsonElement jsonElement)
+ public void UpdateByKey(object key, TEntity entity, UpdateBehavior behavior)
{
- var updateClauses = _jsonHelper.ConvertJsonElementToUpdateClause(jsonElement);
- _table.Update(_dbConnection, WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key), updateClauses);
+ _table.Update(_dbConnection, WhereClause.Create().Eq(_table.KeyColumn.ColumnName, key),
+ ConvertEntityToUpdateClauses(entity, behavior));
}
public void DeleteByKey(object key)
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs
index b7bc6f1..c91c969 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/CrudWebApplicationExtensions.cs
@@ -8,14 +8,16 @@ public static class CrudWebApplicationExtensions
{
if (!context.RequirePermission(permission)) return;
var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();
+ var entityJsonHelper = context.RequestServices.GetRequiredService<EntityJsonHelper<TEntity>>();
var allEntities = crudService.GetAll();
- await context.ResponseJsonAsync(allEntities.Select(e => crudService.JsonHelper.ConvertEntityToDictionary(e)));
+ await context.ResponseJsonAsync(allEntities.Select(e => entityJsonHelper.ConvertEntityToDictionary(e)));
});
app.MapGet(path + "/{key}", async (context) =>
{
if (!context.RequirePermission(permission)) return;
var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();
+ var entityJsonHelper = context.RequestServices.GetRequiredService<EntityJsonHelper<TEntity>>();
var key = context.Request.RouteValues["key"]?.ToString();
if (key == null)
{
@@ -24,23 +26,25 @@ public static class CrudWebApplicationExtensions
}
var entity = crudService.GetByKey(key);
- await context.ResponseJsonAsync(crudService.JsonHelper.ConvertEntityToDictionary(entity));
+ await context.ResponseJsonAsync(entityJsonHelper.ConvertEntityToDictionary(entity));
});
app.MapPost(path, async (context) =>
{
if (!context.RequirePermission(permission)) return;
var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();
+ var entityJsonHelper = context.RequestServices.GetRequiredService<EntityJsonHelper<TEntity>>();
var jsonDocument = await context.Request.ReadJsonAsync();
- var key = crudService.Create(jsonDocument.RootElement);
- await context.ResponseJsonAsync(crudService.JsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key)));
+ var key = crudService.Create(entityJsonHelper.ConvertJsonToEntityForInsert(jsonDocument.RootElement));
+ await context.ResponseJsonAsync(entityJsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key)));
});
app.MapPatch(path + "/{key}", async (context) =>
{
if (!context.RequirePermission(permission)) return;
- var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();
var key = context.Request.RouteValues["key"]?.ToString();
+ var crudService = context.RequestServices.GetRequiredService<CrudService<TEntity>>();
+ var entityJsonHelper = context.RequestServices.GetRequiredService<EntityJsonHelper<TEntity>>();
if (key == null)
{
await context.ResponseMessageAsync("Please specify a key in path.");
@@ -48,9 +52,9 @@ public static class CrudWebApplicationExtensions
}
var jsonDocument = await context.Request.ReadJsonAsync();
- crudService.UpdateByKey(key, jsonDocument.RootElement);
-
- await context.ResponseJsonAsync(crudService.JsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key)));
+ var entity = entityJsonHelper.ConvertJsonToEntityForUpdate(jsonDocument.RootElement, out var updateBehavior);
+ crudService.UpdateByKey(key, entity, updateBehavior);
+ await context.ResponseJsonAsync(entityJsonHelper.ConvertEntityToDictionary(crudService.GetByKey(key)));
});
app.MapDelete(path + "/{key}", async (context) =>
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/DbConnectionFactory.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/DbConnectionFactory.cs
index e8f8abf..85b818b 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/DbConnectionFactory.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/DbConnectionFactory.cs
@@ -7,6 +7,7 @@ namespace CrupestApi.Commons.Crud;
public interface IDbConnectionFactory
{
IDbConnection Get(string? name = null);
+ bool ShouldDisposeConnection { get; }
}
public class SqliteConnectionFactory : IDbConnectionFactory
@@ -28,4 +29,44 @@ public class SqliteConnectionFactory : IDbConnectionFactory
return new SqliteConnection(connectionString);
}
+
+ public bool ShouldDisposeConnection => true;
+}
+
+public class SqliteMemoryConnectionFactory : IDbConnectionFactory, IDisposable
+{
+ private readonly Dictionary<string, IDbConnection> _connections = new();
+
+ public IDbConnection Get(string? name = null)
+ {
+ name = name ?? "crupest-api";
+
+ if (_connections.TryGetValue(name, out var connection))
+ {
+ return connection;
+ }
+ else
+ {
+ var connectionString = new SqliteConnectionStringBuilder()
+ {
+ DataSource = ":memory:",
+ Mode = SqliteOpenMode.ReadWriteCreate
+ }.ToString();
+
+ connection = new SqliteConnection(connectionString);
+ _connections.Add(name, connection);
+ return connection;
+ }
+ }
+
+ public bool ShouldDisposeConnection => false;
+
+
+ public void Dispose()
+ {
+ foreach (var connection in _connections.Values)
+ {
+ connection.Dispose();
+ }
+ }
}
diff --git a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
index 1265fe9..4489307 100644
--- a/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
+++ b/docker/crupest-api/CrupestApi/CrupestApi.Commons/Crud/EntityJsonHelper.cs
@@ -17,7 +17,7 @@ public class EntityJsonHelper<TEntity> where TEntity : class
_jsonSerializerOptions = jsonSerializerOptions;
}
- public virtual Dictionary<string, object?> ConvertEntityToDictionary(TEntity entity, bool includeNonColumnProperties = false)
+ public Dictionary<string, object?> ConvertEntityToDictionary(TEntity entity, bool includeNonColumnProperties = false)
{
var result = new Dictionary<string, object?>();
@@ -40,131 +40,75 @@ public class EntityJsonHelper<TEntity> where TEntity : class
return result;
}
- public virtual string ConvertEntityToJson(TEntity entity, bool includeNonColumnProperties = false)
+ public string ConvertEntityToJson(TEntity entity, bool includeNonColumnProperties = false)
{
var dictionary = ConvertEntityToDictionary(entity, includeNonColumnProperties);
return JsonSerializer.Serialize(dictionary, _jsonSerializerOptions.CurrentValue);
}
- public virtual IInsertClause ConvertJsonElementToInsertClauses(JsonElement rootElement)
+ public TEntity ConvertJsonToEntityForInsert(JsonElement jsonElement)
{
- var insertClause = InsertClause.Create();
-
- if (rootElement.ValueKind != JsonValueKind.Object)
- {
- throw new UserException("The root element must be an object.");
- }
+ if (jsonElement.ValueKind is not JsonValueKind.Object)
+ throw new ArgumentException("The jsonElement must be an object.");
+ var result = Activator.CreateInstance<TEntity>();
foreach (var column in _table.PropertyColumns)
{
- object? value = null;
- if (rootElement.TryGetProperty(column.ColumnName, out var propertyElement))
- {
- value = propertyElement.ValueKind switch
- {
- 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 (column.IsGenerated && value is not null)
- {
- throw new UserException($"The property {column.ColumnName} is generated. You cannot specify its value.");
- }
-
- if (column.IsNotNull && !column.CanBeGenerated && value is null)
+ if (jsonElement.TryGetProperty(column.ColumnName, out var value))
{
- throw new UserException($"The property {column.ColumnName} can't be null or generated. But you specify a null value.");
+ var realValue = column.ColumnType.ConvertFromDatabase(value);
+ column.PropertyInfo!.SetValue(result, realValue);
}
-
- insertClause.Add(column.ColumnName, value);
}
- return insertClause;
+ return result;
}
- public IInsertClause ConvertJsonToInsertClauses(string json)
+ public TEntity ConvertJsonToEntityForInsert(string json)
{
- var document = JsonSerializer.Deserialize<JsonDocument>(json, _jsonSerializerOptions.CurrentValue)!;
- return ConvertJsonElementToInsertClauses(document.RootElement);
+ var jsonElement = JsonSerializer.Deserialize<JsonElement>(json, _jsonSerializerOptions.CurrentValue);
+ return ConvertJsonToEntityForInsert(jsonElement!);
}
- public IUpdateClause ConvertJsonElementToUpdateClause(JsonElement rootElement, bool saveNull)
+ public TEntity ConvertJsonToEntityForUpdate(JsonElement jsonElement, out UpdateBehavior updateBehavior)
{
- var updateClause = UpdateClause.Create();
+ if (jsonElement.ValueKind is not JsonValueKind.Object)
+ throw new UserException("The jsonElement must be an object.");
- if (rootElement.ValueKind != JsonValueKind.Object)
- {
- throw new UserException("The root element must be an object.");
- }
+ updateBehavior = UpdateBehavior.None;
- foreach (var column in _table.PropertyColumns)
+ if (jsonElement.TryGetProperty("$saveNull", out var saveNullValue))
{
- object? value = null;
-
- if (rootElement.TryGetProperty(column.ColumnName, out var propertyElement))
+ if (saveNullValue.ValueKind is JsonValueKind.True)
{
- value = propertyElement.ValueKind switch
- {
- 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 (column.IsNoUpdate && (value is not null || saveNull))
- {
- throw new UserException($"The property {column.ColumnName} is not updatable. You cannot specify its value.");
- }
+ updateBehavior |= UpdateBehavior.SaveNull;
}
+ else if (saveNullValue.ValueKind is JsonValueKind.False)
+ {
- if (value is null && !saveNull)
+ }
+ else
{
- continue;
+ throw new UserException("The $saveNull must be a boolean.");
}
-
- updateClause.Add(column.ColumnName, value ?? DbNullValue.Instance);
}
- return updateClause;
- }
-
- public IUpdateClause ConvertJsonElementToUpdateClause(JsonElement rootElement)
- {
- var updateClause = UpdateClause.Create();
-
- if (rootElement.ValueKind != JsonValueKind.Object)
- {
- throw new UserException("The root element must be an object.");
- }
-
- bool saveNull = false;
-
- if (rootElement.TryGetProperty("$saveNull", out var propertyElement))
+ var result = Activator.CreateInstance<TEntity>();
+ foreach (var column in _table.PropertyColumns)
{
- if (propertyElement.ValueKind is not JsonValueKind.True or JsonValueKind.False)
+ if (jsonElement.TryGetProperty(column.ColumnName, out var value))
{
- throw new UserException("$saveNull can only be true or false.");
- }
-
- if (propertyElement.ValueKind is JsonValueKind.True)
- {
- saveNull = true;
+ var realValue = column.ColumnType.ConvertFromDatabase(value);
+ column.PropertyInfo!.SetValue(result, realValue);
}
}
- return ConvertJsonElementToUpdateClause(rootElement, saveNull);
+ return result;
}
- public IUpdateClause ConvertJsonToUpdateClause(string json)
+ public TEntity ConvertJsonToEntityForUpdate(string json, out UpdateBehavior updateBehavior)
{
- var document = JsonSerializer.Deserialize<JsonDocument>(json, _jsonSerializerOptions.CurrentValue)!;
- return ConvertJsonElementToUpdateClause(document.RootElement);
+ var jsonElement = JsonSerializer.Deserialize<JsonElement>(json, _jsonSerializerOptions.CurrentValue);
+ return ConvertJsonToEntityForUpdate(jsonElement!, out updateBehavior);
}
}