.NET WinForms-Anwendung (Core, Modules/CongressTrading, UI). Enthaelt .gitignore und settings.example.json als Konfigurationsvorlage. Echte settings.json mit Zugangsdaten ist bewusst ausgeschlossen. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
81 lines
3.5 KiB
C#
81 lines
3.5 KiB
C#
using IBKRTrader.Core.Database;
|
|
using IBKRTrader.Core.Logging;
|
|
|
|
namespace IBKRTrader.Modules.CongressTrading.Database;
|
|
|
|
/// <summary>
|
|
/// Legt die ct_xxx-Tabellen idempotent an.
|
|
/// Namensschema: ct_{tabellenname} gemäß Architekturregeln.
|
|
/// </summary>
|
|
public class CongressMigrations
|
|
{
|
|
private readonly DatabaseService _db;
|
|
private readonly LoggingService _logger;
|
|
|
|
public CongressMigrations(DatabaseService db, LoggingService logger)
|
|
{
|
|
_db = db;
|
|
_logger = logger;
|
|
}
|
|
|
|
public async Task RunAsync()
|
|
{
|
|
_logger.Info("CT", "Starte CongressTrading-Datenbankmigrationen...");
|
|
await CreateCongressMemberTableAsync();
|
|
await CreateCongressTradeTableAsync();
|
|
_logger.Info("CT", "CongressTrading-Migrationen abgeschlossen.");
|
|
}
|
|
|
|
private Task CreateCongressMemberTableAsync() => _db.ExecuteAsync(@"
|
|
CREATE TABLE IF NOT EXISTS `ct_congressMember` (
|
|
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
`bio_id` VARCHAR(20) NOT NULL UNIQUE,
|
|
`name` VARCHAR(200),
|
|
`party` VARCHAR(50),
|
|
`state` VARCHAR(50),
|
|
`chamber` VARCHAR(10),
|
|
`profile_url` VARCHAR(500),
|
|
`first_seen` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
`last_updated` DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
ON UPDATE CURRENT_TIMESTAMP,
|
|
INDEX `idx_bio_id` (`bio_id`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
|
|
|
private async Task CreateCongressTradeTableAsync()
|
|
{
|
|
// Tabelle anlegen
|
|
await _db.ExecuteAsync(@"
|
|
CREATE TABLE IF NOT EXISTS `ct_trade` (
|
|
`id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
|
`trade_id` VARCHAR(20) NOT NULL UNIQUE,
|
|
`member_bio_id` VARCHAR(20) NOT NULL,
|
|
`issuer_name` VARCHAR(500),
|
|
`issuer_id` VARCHAR(20),
|
|
`ticker` VARCHAR(20),
|
|
`trade_type` VARCHAR(50),
|
|
`chamber` VARCHAR(20),
|
|
`owner` VARCHAR(50),
|
|
`value` DECIMAL(18,2),
|
|
`size_range_low` BIGINT,
|
|
`size_range_high` BIGINT,
|
|
`trade_date` DATE,
|
|
`published_date` DATE,
|
|
`detail_url` VARCHAR(500),
|
|
`details_fetched` TINYINT(1) NOT NULL DEFAULT 1,
|
|
`scraped_at` DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
INDEX `idx_member` (`member_bio_id`),
|
|
INDEX `idx_trade_date` (`trade_date`),
|
|
INDEX `idx_ticker` (`ticker`),
|
|
INDEX `idx_details` (`details_fetched`)
|
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;");
|
|
|
|
// Idempotente Spalten-Migrationen (für bestehende DBs)
|
|
await _db.ExecuteAsync("ALTER TABLE `ct_trade` ADD COLUMN IF NOT EXISTS `details_fetched` TINYINT(1) NOT NULL DEFAULT 1;");
|
|
await _db.ExecuteAsync("ALTER TABLE `ct_trade` ADD COLUMN IF NOT EXISTS `chamber` VARCHAR(20);");
|
|
await _db.ExecuteAsync("ALTER TABLE `ct_trade` ADD COLUMN IF NOT EXISTS `owner` VARCHAR(50);");
|
|
await _db.ExecuteAsync("ALTER TABLE `ct_trade` ADD COLUMN IF NOT EXISTS `value` DECIMAL(18,2);");
|
|
await _db.ExecuteAsync("ALTER TABLE `ct_trade` ADD INDEX IF NOT EXISTS `idx_details` (`details_fetched`);");
|
|
}
|
|
}
|
|
|