Files
Alex Bezdieniezhnykh a493606f64 correct app close
fix publishing
2025-03-03 19:37:07 +02:00

151 lines
5.2 KiB
C#

using System.Data.SQLite;
using System.Diagnostics;
using System.IO;
using Azaion.Common.DTO;
using Azaion.Common.DTO.Config;
using LinqToDB;
using LinqToDB.Data;
using LinqToDB.DataProvider.SQLite;
using LinqToDB.Mapping;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace Azaion.Common.Database;
public interface IDbFactory
{
Task<T> Run<T>(Func<AnnotationsDb, Task<T>> func);
Task Run(Func<AnnotationsDb, Task> func);
void SaveToDisk();
Task DeleteAnnotations(List<Annotation> annotations, CancellationToken cancellationToken = default);
Task DeleteAnnotations(List<string> annotationNames, CancellationToken cancellationToken = default);
}
public class DbFactory : IDbFactory
{
private readonly AnnotationConfig _annConfig;
private string MemoryConnStr => "Data Source=:memory:";
private readonly SQLiteConnection _memoryConnection;
private readonly DataOptions _memoryDataOptions;
private string FileConnStr => $"Data Source={_annConfig.AnnotationsDbFile}";
private readonly SQLiteConnection _fileConnection;
private readonly DataOptions _fileDataOptions;
public DbFactory(IOptions<AnnotationConfig> annConfig, ILogger<DbFactory> logger)
{
_annConfig = annConfig.Value;
_memoryConnection = new SQLiteConnection(MemoryConnStr);
_memoryConnection.Open();
_memoryDataOptions = new DataOptions()
.UseDataProvider(SQLiteTools.GetDataProvider())
.UseConnection(_memoryConnection)
.UseMappingSchema(AnnotationsDbSchemaHolder.MappingSchema)
;//.UseTracing(TraceLevel.Info, t => logger.LogInformation(t.SqlText));
_fileConnection = new SQLiteConnection(FileConnStr);
_fileDataOptions = new DataOptions()
.UseDataProvider(SQLiteTools.GetDataProvider())
.UseConnection(_fileConnection)
.UseMappingSchema(AnnotationsDbSchemaHolder.MappingSchema);
if (!File.Exists(_annConfig.AnnotationsDbFile))
CreateDb();
_fileConnection.Open();
_fileConnection.BackupDatabase(_memoryConnection, "main", "main", -1, null, -1);
}
private void CreateDb()
{
SQLiteConnection.CreateFile(_annConfig.AnnotationsDbFile);
using var db = new AnnotationsDb(_fileDataOptions);
db.CreateTable<Annotation>();
db.CreateTable<AnnotationName>();
db.CreateTable<Detection>();
db.CreateTable<QueueOffset>();
db.QueueOffsets.BulkCopy(new List<QueueOffset>
{
new()
{
Offset = 0,
QueueName = Constants.MQ_ANNOTATIONS_QUEUE
},
new()
{
Offset = 0,
QueueName = Constants.MQ_ANNOTATIONS_CONFIRM_QUEUE
}
});
}
public async Task<T> Run<T>(Func<AnnotationsDb, Task<T>> func)
{
await using var db = new AnnotationsDb(_memoryDataOptions);
return await func(db);
}
public async Task Run(Func<AnnotationsDb, Task> func)
{
await using var db = new AnnotationsDb(_memoryDataOptions);
await func(db);
}
public void SaveToDisk()
{
_memoryConnection.BackupDatabase(_fileConnection, "main", "main", -1, null, -1);
}
public async Task DeleteAnnotations(List<Annotation> annotations, CancellationToken cancellationToken = default)
{
var names = annotations.Select(x => x.Name).ToList();
await DeleteAnnotations(names, cancellationToken);
}
public async Task DeleteAnnotations(List<string> annotationNames, CancellationToken cancellationToken = default)
{
await Run(async db =>
{
var detDeleted = await db.Detections.DeleteAsync(x => annotationNames.Contains(x.AnnotationName), token: cancellationToken);
var annDeleted = await db.Annotations.DeleteAsync(x => annotationNames.Contains(x.Name), token: cancellationToken);
Console.WriteLine($"Deleted {detDeleted} detections, {annDeleted} annotations");
});
SaveToDisk();
}
}
public static class AnnotationsDbSchemaHolder
{
public static readonly MappingSchema MappingSchema;
static AnnotationsDbSchemaHolder()
{
MappingSchema = new MappingSchema();
var builder = new FluentMappingBuilder(MappingSchema);
var annotationBuilder = builder.Entity<Annotation>();
annotationBuilder.HasTableName(Constants.ANNOTATIONS_TABLENAME)
.HasPrimaryKey(x => x.Name)
.Association(a => a.Detections, (a, d) => a.Name == d.AnnotationName)
.Property(x => x.Time).HasDataType(DataType.Int64).HasConversion(ts => ts.Ticks, t => new TimeSpan(t));
annotationBuilder
.Ignore(x => x.Milliseconds)
.Ignore(x => x.Classes)
.Ignore(x => x.Classes)
.Ignore(x => x.ImagePath)
.Ignore(x => x.LabelPath)
.Ignore(x => x.ThumbPath);
builder.Entity<Detection>()
.HasTableName(Constants.DETECTIONS_TABLENAME);
builder.Entity<AnnotationName>()
.HasTableName(Constants.ANNOTATIONS_QUEUE_TABLENAME);
builder.Build();
}
}