AbbDbContext: Move SqliteConnection extensions to Extensions class
All checks were successful
Test / Run tests (push) Successful in 2m25s
All checks were successful
Test / Run tests (push) Successful in 2m25s
This commit is contained in:
@@ -10,7 +10,6 @@ using Microsoft.Data.Sqlite;
|
|||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Elwig.Models.Dtos;
|
using Elwig.Models.Dtos;
|
||||||
using System.Reflection;
|
|
||||||
using System.Data;
|
using System.Data;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
@@ -117,40 +116,6 @@ namespace Elwig.Helpers {
|
|||||||
return cnx;
|
return cnx;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ExecuteBatch(SqliteConnection cnx, string sql) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = sql;
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
while (await reader.NextResultAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task ExecuteEmbeddedScript(SqliteConnection cnx, Assembly asm, string name) {
|
|
||||||
using var stream = asm.GetManifestResourceStream(name) ?? throw new FileNotFoundException("Unable to load embedded resource");
|
|
||||||
using var reader = new StreamReader(stream);
|
|
||||||
await ExecuteBatch(cnx, await reader.ReadToEndAsync());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<object?> ExecuteScalar(SqliteConnection cnx, string sql) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = sql;
|
|
||||||
return await cmd.ExecuteScalarAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<(string Table, long RowId, string Parent, long FkId)[]> ForeignKeyCheck(SqliteConnection cnx) {
|
|
||||||
using var cmd = cnx.CreateCommand();
|
|
||||||
cmd.CommandText = "PRAGMA foreign_key_check";
|
|
||||||
using var reader = await cmd.ExecuteReaderAsync();
|
|
||||||
var list = new List<(string, long, string, long)>();
|
|
||||||
while (await reader.ReadAsync()) {
|
|
||||||
var table = reader.GetString(0);
|
|
||||||
var rowid = reader.GetInt64(1);
|
|
||||||
var parent = reader.GetString(2);
|
|
||||||
var fkid = reader.GetInt64(3);
|
|
||||||
list.Add((table, rowid, parent, fkid));
|
|
||||||
}
|
|
||||||
return [.. list];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) {
|
||||||
optionsBuilder.UseSqlite(ConnectionString);
|
optionsBuilder.UseSqlite(ConnectionString);
|
||||||
optionsBuilder.UseLazyLoadingProxies();
|
optionsBuilder.UseLazyLoadingProxies();
|
||||||
|
|||||||
@@ -16,10 +16,10 @@ namespace Elwig.Helpers {
|
|||||||
public static async Task<Version> CheckDb() {
|
public static async Task<Version> CheckDb() {
|
||||||
using var cnx = AppDbContext.Connect();
|
using var cnx = AppDbContext.Connect();
|
||||||
|
|
||||||
var applId = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA application_id") ?? 0;
|
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
|
||||||
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
|
if (applId != 0x454C5747) throw new Exception($"Invalid application_id in database (0x{applId:X08})");
|
||||||
|
|
||||||
var schemaVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA schema_version") ?? 0;
|
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
|
||||||
VersionOffset = (int)(schemaVers % 100);
|
VersionOffset = (int)(schemaVers % 100);
|
||||||
if (VersionOffset != 0) {
|
if (VersionOffset != 0) {
|
||||||
// schema was modified manually/externally
|
// schema was modified manually/externally
|
||||||
@@ -27,12 +27,12 @@ namespace Elwig.Helpers {
|
|||||||
}
|
}
|
||||||
await UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion);
|
await UpdateDbSchema(cnx, (int)(schemaVers / 100), RequiredSchemaVersion);
|
||||||
|
|
||||||
var userVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA user_version") ?? 0;
|
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0;
|
||||||
var v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF));
|
var v = new Version((int)(userVers >> 24), (int)((userVers >> 16) & 0xFF), (int)((userVers >> 8) & 0xFF), (int)(userVers & 0xFF));
|
||||||
|
|
||||||
if (App.Version > v) {
|
if (App.Version > v) {
|
||||||
long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision;
|
long vers = (App.Version.Major << 24) | (App.Version.Minor << 16) | (App.Version.Build << 8) | App.Version.Revision;
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"PRAGMA user_version = {vers}");
|
await cnx.ExecuteBatch($"PRAGMA user_version = {vers}");
|
||||||
}
|
}
|
||||||
|
|
||||||
return v;
|
return v;
|
||||||
@@ -67,20 +67,20 @@ namespace Elwig.Helpers {
|
|||||||
if (toExecute.Count == 0)
|
if (toExecute.Count == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, """
|
await cnx.ExecuteBatch("""
|
||||||
PRAGMA locking_mode = EXCLUSIVE;
|
PRAGMA locking_mode = EXCLUSIVE;
|
||||||
BEGIN EXCLUSIVE;
|
BEGIN EXCLUSIVE;
|
||||||
""");
|
""");
|
||||||
foreach (var script in toExecute) {
|
foreach (var script in toExecute) {
|
||||||
await AppDbContext.ExecuteEmbeddedScript(cnx, asm, script);
|
await cnx.ExecuteEmbeddedScript(asm, script);
|
||||||
}
|
}
|
||||||
var violations = await AppDbContext.ForeignKeyCheck(cnx);
|
var violations = await cnx.ForeignKeyCheck();
|
||||||
if (violations.Length > 0) {
|
if (violations.Length > 0) {
|
||||||
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
|
throw new Exception($"Foreign key violations ({violations.Length}):\n" + string.Join("\n", violations
|
||||||
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
|
.Select(v => $"{v.Table} - {v.RowId} - {v.Parent} - {v.FkId}")));
|
||||||
}
|
}
|
||||||
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
COMMIT;
|
COMMIT;
|
||||||
VACUUM;
|
VACUUM;
|
||||||
PRAGMA schema_version = {toVersion * 100 + VersionOffset};
|
PRAGMA schema_version = {toVersion * 100 + VersionOffset};
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
|
|
||||||
public async Task FinishSeason() {
|
public async Task FinishSeason() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
UPDATE season
|
UPDATE season
|
||||||
SET (start_date, end_date) = (SELECT MIN(date), MAX(date) FROM delivery WHERE year = {Year})
|
SET (start_date, end_date) = (SELECT MIN(date), MAX(date) FROM delivery WHERE year = {Year})
|
||||||
WHERE year = {Year};
|
WHERE year = {Year};
|
||||||
@@ -37,7 +37,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) {
|
public async Task AutoAdjustBusinessShares(DateOnly date, int allowanceKg = 0, double allowanceBs = 0, int allowanceKgPerBs = 0, double allowanceRel = 0, int addMinBs = 1) {
|
||||||
if (addMinBs < 1) addMinBs = 1;
|
if (addMinBs < 1) addMinBs = 1;
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
UPDATE member
|
UPDATE member
|
||||||
SET business_shares = member.business_shares - h.business_shares
|
SET business_shares = member.business_shares - h.business_shares
|
||||||
FROM member_history h
|
FROM member_history h
|
||||||
@@ -66,7 +66,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
|
|
||||||
public async Task UnAdjustBusinessShares() {
|
public async Task UnAdjustBusinessShares() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
UPDATE member
|
UPDATE member
|
||||||
SET business_shares = member.business_shares - h.business_shares
|
SET business_shares = member.business_shares - h.business_shares
|
||||||
FROM member_history h
|
FROM member_history h
|
||||||
@@ -157,9 +157,9 @@ namespace Elwig.Helpers.Billing {
|
|||||||
lastMgNr = mgnr;
|
lastMgNr = mgnr;
|
||||||
}
|
}
|
||||||
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}");
|
await cnx.ExecuteBatch($"UPDATE delivery_part_bucket SET value = 0 WHERE year = {Year}");
|
||||||
if (inserts.Count > 0) {
|
if (inserts.Count > 0) {
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
VALUES {string.Join(",\n ", inserts.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '{i.Item4}', {i.Item5})"))}
|
||||||
ON CONFLICT DO UPDATE
|
ON CONFLICT DO UPDATE
|
||||||
@@ -237,7 +237,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
if (needed == 0) break;
|
if (needed == 0) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
INSERT INTO delivery_part_bucket (year, did, dpnr, bktnr, discr, value)
|
||||||
VALUES {string.Join(",\n ", posChanges.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '', {i.Item4})"))}
|
VALUES {string.Join(",\n ", posChanges.Select(i => $"({Year}, {i.Item1}, {i.Item2}, {i.Item3}, '', {i.Item4})"))}
|
||||||
ON CONFLICT DO UPDATE
|
ON CONFLICT DO UPDATE
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
public async Task Commit() {
|
public async Task Commit() {
|
||||||
await Revert();
|
await Revert();
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers)
|
INSERT INTO credit (year, tgnr, mgnr, avnr, net_amount, prev_net_amount, vat, modifiers, prev_modifiers)
|
||||||
SELECT s.year,
|
SELECT s.year,
|
||||||
COALESCE(t.tgnr, 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr) AS tgnr,
|
COALESCE(t.tgnr, 0) + ROW_NUMBER() OVER(ORDER BY m.mgnr) AS tgnr,
|
||||||
@@ -82,27 +82,27 @@ namespace Elwig.Helpers.Billing {
|
|||||||
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
|
LEFT JOIN payment_custom x ON (x.year, x.mgnr) = (s.year, m.mgnr)
|
||||||
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
WHERE s.year = {Year} AND v.avnr = {AvNr};
|
||||||
""");
|
""");
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
UPDATE payment_variant SET test_variant = FALSE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Revert() {
|
public async Task Revert() {
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
DELETE FROM credit WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM credit WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
UPDATE payment_variant SET test_variant = TRUE WHERE (year, avnr) = ({Year}, {AvNr});
|
UPDATE payment_variant SET test_variant = TRUE WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task SetCalcTime(SqliteConnection cnx) {
|
protected async Task SetCalcTime(SqliteConnection cnx) {
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
UPDATE payment_variant SET calc_time = UNIXEPOCH() WHERE (year, avnr) = ({Year}, {AvNr})
|
UPDATE payment_variant SET calc_time = UNIXEPOCH() WHERE (year, avnr) = ({Year}, {AvNr})
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async Task DeleteInDb(SqliteConnection cnx) {
|
protected async Task DeleteInDb(SqliteConnection cnx) {
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
DELETE FROM payment_delivery_part_bucket WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_delivery_part_bucket WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_delivery_part WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
DELETE FROM payment_member WHERE (year, avnr) = ({Year}, {AvNr});
|
DELETE FROM payment_member WHERE (year, avnr) = ({Year}, {AvNr});
|
||||||
@@ -116,7 +116,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
var multiplier = 0.50;
|
var multiplier = 0.50;
|
||||||
var includePredecessor = true;
|
var includePredecessor = true;
|
||||||
var modName = "Treue%";
|
var modName = "Treue%";
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT c.year, {AvNr}, s.mgnr, 0,
|
SELECT c.year, {AvNr}, s.mgnr, 0,
|
||||||
ROUND(s.sum * COALESCE(m.abs, 0)),
|
ROUND(s.sum * COALESCE(m.abs, 0)),
|
||||||
@@ -138,7 +138,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
mod_rel = mod_rel + excluded.mod_rel
|
mod_rel = mod_rel + excluded.mod_rel
|
||||||
""");
|
""");
|
||||||
}
|
}
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_member (year, avnr, mgnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT x.year, {AvNr}, x.mgnr, 0, COALESCE(x.mod_abs * POW(10, s.precision - 2), 0), COALESCE(x.mod_rel, 0)
|
SELECT x.year, {AvNr}, x.mgnr, 0, COALESCE(x.mod_abs * POW(10, s.precision - 2), 0), COALESCE(x.mod_rel, 0)
|
||||||
FROM payment_custom x
|
FROM payment_custom x
|
||||||
@@ -194,7 +194,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
var msg = invalid.Count == 0 ? null : "Für folgende Sorten wurde noch keine Preiskurve festgelegt: " + string.Join(", ", invalid);
|
var msg = invalid.Count == 0 ? null : "Für folgende Sorten wurde noch keine Preiskurve festgelegt: " + string.Join(", ", invalid);
|
||||||
if (msg != null && strict)
|
if (msg != null && strict)
|
||||||
throw new KeyNotFoundException(msg);
|
throw new KeyNotFoundException(msg);
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount)
|
INSERT INTO payment_delivery_part_bucket (year, did, dpnr, bktnr, avnr, price, amount)
|
||||||
VALUES {string.Join(",\n ", inserts.Select(i => $"({i.Year}, {i.DId}, {i.DPNr}, {i.BktNr}, {AvNr}, {i.Price}, {i.Amount})"))};
|
VALUES {string.Join(",\n ", inserts.Select(i => $"({i.Year}, {i.DId}, {i.DPNr}, {i.BktNr}, {AvNr}, {i.Price}, {i.Amount})"))};
|
||||||
""");
|
""");
|
||||||
@@ -205,7 +205,7 @@ namespace Elwig.Helpers.Billing {
|
|||||||
protected async Task CalculateDeliveryModifiers(SqliteConnection cnx) {
|
protected async Task CalculateDeliveryModifiers(SqliteConnection cnx) {
|
||||||
var netMod = Data.NetWeightModifier.ToString().Replace(',', '.');
|
var netMod = Data.NetWeightModifier.ToString().Replace(',', '.');
|
||||||
var grossMod = Data.GrossWeightModifier.ToString().Replace(',', '.');
|
var grossMod = Data.GrossWeightModifier.ToString().Replace(',', '.');
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
|
INSERT INTO payment_delivery_part (year, did, dpnr, avnr, net_amount, mod_abs, mod_rel)
|
||||||
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, 0, IIF(d.net_weight, {netMod}, {grossMod})
|
SELECT d.year, d.did, d.dpnr, {AvNr}, 0, 0, IIF(d.net_weight, {netMod}, {grossMod})
|
||||||
FROM delivery_part d
|
FROM delivery_part d
|
||||||
|
|||||||
@@ -11,9 +11,9 @@ namespace Elwig.Helpers.Export {
|
|||||||
private static async Task<(long? ApplicationId, string? UserVersion, long? SchemaVersion, long FileSize)> GetMeta() {
|
private static async Task<(long? ApplicationId, string? UserVersion, long? SchemaVersion, long FileSize)> GetMeta() {
|
||||||
long size = new FileInfo(App.Config.DatabaseFile).Length;
|
long size = new FileInfo(App.Config.DatabaseFile).Length;
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
var applId = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA application_id");
|
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id");
|
||||||
var userVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA user_version");
|
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version");
|
||||||
var schemaVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA schema_version");
|
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version");
|
||||||
return (applId, userVers != null ? $"{userVers >> 24}.{(userVers >> 16) & 0xFF}.{(userVers >> 8) & 0xFF}.{userVers & 0xFF}" : null, schemaVers, size);
|
return (applId, userVers != null ? $"{userVers >> 24}.{(userVers >> 16) & 0xFF}.{(userVers >> 8) & 0xFF}.{userVers & 0xFF}" : null, schemaVers, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,9 +100,9 @@ namespace Elwig.Helpers.Export {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var applId = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA application_id") ?? 0;
|
var applId = (long?)await cnx.ExecuteScalar("PRAGMA application_id") ?? 0;
|
||||||
var userVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA user_version") ?? 0;
|
var userVers = (long?)await cnx.ExecuteScalar("PRAGMA user_version") ?? 0;
|
||||||
var schemaVers = (long?)await AppDbContext.ExecuteScalar(cnx, "PRAGMA schema_version") ?? 0;
|
var schemaVers = (long?)await cnx.ExecuteScalar("PRAGMA schema_version") ?? 0;
|
||||||
|
|
||||||
await writer.WriteLineAsync($"-- Elwig database dump, {DateTime.Now:yyyy-MM-dd, HH:mm:ss}");
|
await writer.WriteLineAsync($"-- Elwig database dump, {DateTime.Now:yyyy-MM-dd, HH:mm:ss}");
|
||||||
await writer.WriteLineAsync($"-- {Environment.MachineName}, Zwst. {App.BranchName}, {App.Client.Name}");
|
await writer.WriteLineAsync($"-- {Environment.MachineName}, Zwst. {App.BranchName}, {App.Client.Name}");
|
||||||
@@ -224,7 +224,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
File.Move(filename, App.Config.DatabaseFile, false);
|
File.Move(filename, App.Config.DatabaseFile, false);
|
||||||
|
|
||||||
using var cnx = await AppDbContext.ConnectAsync();
|
using var cnx = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteBatch(cnx, "VACUUM");
|
await cnx.ExecuteBatch("VACUUM");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async Task ImportSql(StreamReader reader) {
|
public static async Task ImportSql(StreamReader reader) {
|
||||||
@@ -232,7 +232,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
File.Delete(newName);
|
File.Delete(newName);
|
||||||
try {
|
try {
|
||||||
using (var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{newName}\"; Mode=ReadWriteCreate; Foreign Keys=False; Cache=Default; Pooling=False")) {
|
using (var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{newName}\"; Mode=ReadWriteCreate; Foreign Keys=False; Cache=Default; Pooling=False")) {
|
||||||
await AppDbContext.ExecuteBatch(cnx, await reader.ReadToEndAsync());
|
await cnx.ExecuteBatch(await reader.ReadToEndAsync());
|
||||||
}
|
}
|
||||||
await ImportSqlite(newName);
|
await ImportSqlite(newName);
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -345,7 +345,7 @@ namespace Elwig.Helpers.Export {
|
|||||||
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
|
$"mtime = {((DateTimeOffset)m.ModifiedAt.ToUniversalTime()).ToUnixTimeSeconds()} " +
|
||||||
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});"));
|
$"WHERE ({primaryKeys[e.Key]}) = ({m.Id1}, {m.Id2});"));
|
||||||
using var cnx = AppDbContext.Connect();
|
using var cnx = AppDbContext.Connect();
|
||||||
await AppDbContext.ExecuteBatch(cnx, $"""
|
await cnx.ExecuteBatch($"""
|
||||||
BEGIN;
|
BEGIN;
|
||||||
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
UPDATE client_parameter SET value = '0' WHERE param = 'ENABLE_TIME_TRIGGERS';
|
||||||
{string.Join("\n", updateStmts)}
|
{string.Join("\n", updateStmts)}
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
|
using Microsoft.Data.Sqlite;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.IO.Hashing;
|
using System.IO.Hashing;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Reflection;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace Elwig.Helpers {
|
namespace Elwig.Helpers {
|
||||||
static partial class Extensions {
|
public static partial class Extensions {
|
||||||
|
|
||||||
[LibraryImport("msvcrt.dll")]
|
[LibraryImport("msvcrt.dll")]
|
||||||
[UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
|
[UnmanagedCallConv(CallConvs = [typeof(System.Runtime.CompilerServices.CallConvCdecl)])]
|
||||||
@@ -108,5 +111,39 @@ namespace Elwig.Helpers {
|
|||||||
throw new InvalidDataException($"CRC-32 mismatch in '{entry.FullName}'");
|
throw new InvalidDataException($"CRC-32 mismatch in '{entry.FullName}'");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task ExecuteBatch(this SqliteConnection cnx, string sql) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = sql;
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
while (await reader.NextResultAsync()) ;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ExecuteEmbeddedScript(this SqliteConnection cnx, Assembly asm, string name) {
|
||||||
|
using var stream = asm.GetManifestResourceStream(name) ?? throw new FileNotFoundException("Unable to load embedded resource");
|
||||||
|
using var reader = new StreamReader(stream);
|
||||||
|
await ExecuteBatch(cnx, await reader.ReadToEndAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<object?> ExecuteScalar(this SqliteConnection cnx, string sql) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = sql;
|
||||||
|
return await cmd.ExecuteScalarAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task<(string Table, long RowId, string Parent, long FkId)[]> ForeignKeyCheck(this SqliteConnection cnx) {
|
||||||
|
using var cmd = cnx.CreateCommand();
|
||||||
|
cmd.CommandText = "PRAGMA foreign_key_check";
|
||||||
|
using var reader = await cmd.ExecuteReaderAsync();
|
||||||
|
var list = new List<(string, long, string, long)>();
|
||||||
|
while (await reader.ReadAsync()) {
|
||||||
|
var table = reader.GetString(0);
|
||||||
|
var rowid = reader.GetInt64(1);
|
||||||
|
var parent = reader.GetString(2);
|
||||||
|
var fkid = reader.GetInt64(3);
|
||||||
|
list.Add((table, rowid, parent, fkid));
|
||||||
|
}
|
||||||
|
return [.. list];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ namespace Tests {
|
|||||||
public async Task Setup_1_Database() {
|
public async Task Setup_1_Database() {
|
||||||
AppDbContext.ConnectionStringOverride = $"Data Source=ElwigTestDB; Mode=Memory; Foreign Keys=True; Cache=Shared";
|
AppDbContext.ConnectionStringOverride = $"Data Source=ElwigTestDB; Mode=Memory; Foreign Keys=True; Cache=Shared";
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ namespace Tests.E2ETests {
|
|||||||
public static async Task SetupDatabase() {
|
public static async Task SetupDatabase() {
|
||||||
if (File.Exists(Utils.TestDatabasePath)) File.Delete(Utils.TestDatabasePath);
|
if (File.Exists(Utils.TestDatabasePath)) File.Delete(Utils.TestDatabasePath);
|
||||||
using var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{Utils.TestDatabasePath}\"; Mode=ReadWriteCreate; Foreign Keys=True; Cache=Default; Pooling=False");
|
using var cnx = await AppDbContext.ConnectAsync($"Data Source=\"{Utils.TestDatabasePath}\"; Mode=ReadWriteCreate; Foreign Keys=True; Cache=Default; Pooling=False");
|
||||||
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Create.sql");
|
||||||
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.Insert.sql");
|
||||||
await AppDbContext.ExecuteEmbeddedScript(cnx, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.E2EInsert.sql");
|
await cnx.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.E2EInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
|
|||||||
@@ -12,13 +12,13 @@ namespace Tests.UnitTests.DocumentTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentInsert.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentDelete.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.DocumentDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,13 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingInsert.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingDelete.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.BillingDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
@@ -72,7 +72,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
[TearDown]
|
[TearDown]
|
||||||
public async Task CleanupDatabasePayment() {
|
public async Task CleanupDatabasePayment() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await AppDbContext.ExecuteBatch(Connection, """
|
await Connection.ExecuteBatch("""
|
||||||
DELETE FROM credit;
|
DELETE FROM credit;
|
||||||
DELETE FROM payment_variant;
|
DELETE FROM payment_variant;
|
||||||
DELETE FROM delivery_part_bucket;
|
DELETE FROM delivery_part_bucket;
|
||||||
@@ -115,7 +115,7 @@ namespace Tests.UnitTests.HelperTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Task InsertPaymentVariant(int year, int avnr, string data) {
|
private Task InsertPaymentVariant(int year, int avnr, string data) {
|
||||||
return AppDbContext.ExecuteBatch(Connection!, $"""
|
return Connection!.ExecuteBatch($"""
|
||||||
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, data)
|
INSERT INTO payment_variant (year, avnr, name, date, transfer_date, test_variant, calc_time, data)
|
||||||
VALUES ({year}, {avnr}, 'Test', '2021-01-15', NULL, TRUE, NULL, '{data}');
|
VALUES ({year}, {avnr}, 'Test', '2021-01-15', NULL, TRUE, NULL, '{data}');
|
||||||
""");
|
""");
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ namespace Tests.UnitTests.ServiceTests {
|
|||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public async Task SetupDatabase() {
|
public async Task SetupDatabase() {
|
||||||
Connection = await AppDbContext.ConnectAsync();
|
Connection = await AppDbContext.ConnectAsync();
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceInsert.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceInsert.sql");
|
||||||
}
|
}
|
||||||
|
|
||||||
[OneTimeTearDown]
|
[OneTimeTearDown]
|
||||||
public async Task TeardownDatabase() {
|
public async Task TeardownDatabase() {
|
||||||
if (Connection == null) return;
|
if (Connection == null) return;
|
||||||
await AppDbContext.ExecuteEmbeddedScript(Connection, Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceDelete.sql");
|
await Connection.ExecuteEmbeddedScript(Assembly.GetExecutingAssembly(), "Tests.Resources.Sql.ServiceDelete.sql");
|
||||||
await Connection.DisposeAsync();
|
await Connection.DisposeAsync();
|
||||||
Connection = null;
|
Connection = null;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user