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 Run(Func> func); Task Run(Func func); void SaveToDisk(); } 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 annConfig, ILogger logger) { _annConfig = annConfig.Value; _memoryConnection = new SQLiteConnection(MemoryConnStr); _memoryConnection.Open(); _memoryDataOptions = new DataOptions() .UseDataProvider(SQLiteTools.GetDataProvider()) .UseConnection(_memoryConnection) .UseMappingSchema(AnnotationsDbSchemaHolder.MappingSchema); _ = _memoryDataOptions.UseTracing(TraceLevel.Info, t => logger.LogInformation(t.SqlText)); _fileConnection = new SQLiteConnection(FileConnStr); _fileDataOptions = new DataOptions() .UseDataProvider(SQLiteTools.GetDataProvider()) .UseConnection(_fileConnection) .UseMappingSchema(AnnotationsDbSchemaHolder.MappingSchema); _ = _fileDataOptions.UseTracing(TraceLevel.Info, t => logger.LogInformation(t.SqlText)); 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(); db.CreateTable(); db.CreateTable(); db.CreateTable(); db.QueueOffsets.BulkCopy(new List { new() { Offset = 0, QueueName = Constants.MQ_ANNOTATIONS_QUEUE }, new() { Offset = 0, QueueName = Constants.MQ_ANNOTATIONS_CONFIRM_QUEUE } }); } public async Task Run(Func> func) { await using var db = new AnnotationsDb(_memoryDataOptions); return await func(db); } public async Task Run(Func func) { await using var db = new AnnotationsDb(_memoryDataOptions); await func(db); } public void SaveToDisk() { _memoryConnection.BackupDatabase(_fileConnection, "main", "main", -1, null, -1); } } public static class AnnotationsDbSchemaHolder { public static readonly MappingSchema MappingSchema; static AnnotationsDbSchemaHolder() { MappingSchema = new MappingSchema(); var builder = new FluentMappingBuilder(MappingSchema); builder.Entity() .HasTableName(Constants.ANNOTATIONS_TABLENAME) .HasPrimaryKey(x => x.Name) .Association(a => a.Detections, (a, d) => a.Name == d.AnnotationName); builder.Entity() .HasTableName(Constants.DETECTIONS_TABLENAME); builder.Entity() .HasTableName(Constants.ANNOTATIONS_QUEUE_TABLENAME); builder.Build(); } }