using System.Data; using Dapper; using Foxnouns.DataMigrator.Models; using Newtonsoft.Json; using Npgsql; namespace Foxnouns.DataMigrator; public static class GoDatabase { private static NpgsqlDataSource? _dataSource; public static async Task GetConnectionAsync() { if (_dataSource != null) return await _dataSource.OpenConnectionAsync(); DefaultTypeMap.MatchNamesWithUnderscores = true; SqlMapper.RemoveTypeMap(typeof(ulong)); SqlMapper.AddTypeHandler(new UlongEncodeAsLongHandler()); SqlMapper.AddTypeHandler(new JsonTypeHandler()); SqlMapper.AddTypeHandler(new JsonTypeHandler>()); SqlMapper.AddTypeHandler(new JsonTypeHandler()); SqlMapper.AddTypeHandler(new UlongListHandler()); string dsn = Environment.GetEnvironmentVariable("GO_DATABASE") ?? throw new Exception("$GO_DATABASE is not set"); var dataSourceBuilder = new NpgsqlDataSourceBuilder(dsn); dataSourceBuilder.UseJsonNet(); _dataSource = dataSourceBuilder.Build(); return await _dataSource.OpenConnectionAsync(); } // dapper why // taken from https://codeberg.org/starshine/catalogger/src/branch/main/Catalogger.Backend/Database/DatabasePool.cs private class UlongEncodeAsLongHandler : SqlMapper.TypeHandler { public override void SetValue(IDbDataParameter parameter, ulong value) => parameter.Value = (long)value; public override ulong Parse(object value) => // Cast to long to unbox, then to ulong (???) (ulong)(long)value; } private class UlongListHandler : SqlMapper.TypeHandler> { public override void SetValue(IDbDataParameter parameter, List? value) => parameter.Value = value?.Select(i => (long)i).ToArray(); public override List? Parse(object value) => ((long[])value).Select(i => (ulong)i).ToList(); } private class JsonTypeHandler : SqlMapper.TypeHandler { public override void SetValue(IDbDataParameter parameter, T? value) => parameter.Value = JsonConvert.SerializeObject(value); public override T? Parse(object value) { var json = (string)value; return JsonConvert.DeserializeObject(json) ?? default; } } }