From a31117c8e329071f0b46b3da19aa31d41c8d8b6a Mon Sep 17 00:00:00 2001 From: Ronny Gunawan <3048897+ronnygunawan@users.noreply.github.com> Date: Sat, 17 Feb 2024 20:06:42 +0700 Subject: [PATCH] Add pileg_dpr_dapil --- .../SQL/SQLCommandHandler.cs | 3 +- .../Pemilu2024/PilegDPRPerDapilDataSource.cs | 158 ++++++++++++++++++ ...ce.cs => PilegDPRPerProvinsiDataSource.cs} | 10 +- .../Pemilu2024/ServiceCollectionExtensions.cs | 3 +- BotNet.Services/Pemilu2024/SirekapClient.cs | 11 +- BotNet.Services/Pemilu2024/Types.cs | 50 +++++- 6 files changed, 220 insertions(+), 15 deletions(-) create mode 100644 BotNet.Services/Pemilu2024/PilegDPRPerDapilDataSource.cs rename BotNet.Services/Pemilu2024/{PilegDPRDataSource.cs => PilegDPRPerProvinsiDataSource.cs} (91%) diff --git a/BotNet.CommandHandlers/SQL/SQLCommandHandler.cs b/BotNet.CommandHandlers/SQL/SQLCommandHandler.cs index 0b79a25..b207a2f 100644 --- a/BotNet.CommandHandlers/SQL/SQLCommandHandler.cs +++ b/BotNet.CommandHandlers/SQL/SQLCommandHandler.cs @@ -57,7 +57,8 @@ await _telegramBotClient.SendTextMessageAsync( chatId: command.Chat.Id, text: $$""" Table '{{table}}' not found. Available tables are: - - pileg_dpr + - pileg_dpr_dapil + - pileg_dpr_provinsi - pilpres - vps diff --git a/BotNet.Services/Pemilu2024/PilegDPRPerDapilDataSource.cs b/BotNet.Services/Pemilu2024/PilegDPRPerDapilDataSource.cs new file mode 100644 index 0000000..e13965c --- /dev/null +++ b/BotNet.Services/Pemilu2024/PilegDPRPerDapilDataSource.cs @@ -0,0 +1,158 @@ +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using BotNet.Services.SQL; +using BotNet.Services.Sqlite; + +namespace BotNet.Services.Pemilu2024 { + public sealed class PilegDPRPerDapilDataSource( + ScopedDatabase scopedDatabase, + SirekapClient sirekapClient + ) : IScopedDataSource { + private const string PKB = "1"; + private const string GERINDRA = "2"; + private const string PDIP = "3"; + private const string GOLKAR = "4"; + private const string NASDEM = "5"; + private const string PARTAI_BURUH = "6"; + private const string GELORA = "7"; + private const string PKS = "8"; + private const string PKN = "9"; + private const string HANURA = "10"; + private const string GARUDA = "11"; + private const string PAN = "12"; + private const string PBB = "13"; + private const string DEMOKRAT = "14"; + private const string PSI = "15"; + private const string PERINDO = "16"; + private const string PPP = "17"; + private const string PNA = "18"; + private const string GABTHAT = "19"; + private const string PDA = "20"; + private const string PARTAI_ACEH = "21"; + private const string PAS_ACEH = "22"; + private const string PARTAI_SIRA = "23"; + private const string PARTAI_UMMAT = "24"; + private readonly ScopedDatabase _scopedDatabase = scopedDatabase; + private readonly SirekapClient _sirekapClient = sirekapClient; + + public async Task LoadTableAsync(CancellationToken cancellationToken) { + _scopedDatabase.ExecuteNonQuery(""" + CREATE TABLE pileg_dpr_dapil ( + kode_dapil VARCHAR(5) PRIMARY KEY, + dapil VARCHAR(50), + progress REAL, + pkb INTEGER, + gerindra INTEGER, + pdip INTEGER, + golkar INTEGER, + nasdem INTEGER, + partai_buruh INTEGER, + gelora INTEGER, + pks INTEGER, + pkn INTEGER, + hanura INTEGER, + garuda INTEGER, + pan INTEGER, + pbb INTEGER, + demokrat INTEGER, + psi INTEGER, + perindo INTEGER, + ppp INTEGER, + pna INTEGER, + gabthat INTEGER, + pda INTEGER, + partai_aceh INTEGER, + pas_aceh INTEGER, + partai_sira INTEGER, + partai_ummat INTEGER, + total INTEGER + ) + """); + + IList listDapilDPR = await _sirekapClient.GetDapilDPRListAsync(cancellationToken); + Dictionary dapilByKode = listDapilDPR.ToDictionary( + keySelector: dapil => dapil.Kode + ); + + ReportPilegDPRByDapil report = await _sirekapClient.GetReportPilegDPRByDapilAsync(cancellationToken); + + foreach ((string kodeDapil, ReportPilegDPRByDapil.Row? row) in report.RowByKodeDapil.OrderBy(pair => pair.Key)) { + if (row == null) { + _scopedDatabase.ExecuteNonQuery(""" + INSERT INTO pileg_dpr_dapil (kode_dapil, dapil, progress, pkb, gerindra, pdip, golkar, nasdem, partai_buruh, gelora, pks, pkn, hanura, garuda, pan, pbb, demokrat, psi, perindo, ppp, pna, gabthat, pda, partai_aceh, pas_aceh, partai_sira, partai_ummat, total) + VALUES (@kode_dapil, @dapil, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null) + """, + [ + ( "@kode_dapil", kodeDapil ), + ( "@dapil", dapilByKode[kodeDapil].Nama ) + ] + ); + continue; + } + + int? pkb = row.VotesByKodePartai!.TryGetValue(PKB, out int p) ? p : null; + int? gerindra = row.VotesByKodePartai!.TryGetValue(GERINDRA, out int g) ? g : null; + int? pdip = row.VotesByKodePartai!.TryGetValue(PDIP, out int pd) ? pd : null; + int? golkar = row.VotesByKodePartai!.TryGetValue(GOLKAR, out int go) ? go : null; + int? nasdem = row.VotesByKodePartai!.TryGetValue(NASDEM, out int n) ? n : null; + int? partai_buruh = row.VotesByKodePartai!.TryGetValue(PARTAI_BURUH, out int pb) ? pb : null; + int? gelora = row.VotesByKodePartai!.TryGetValue(GELORA, out int ge) ? ge : null; + int? pks = row.VotesByKodePartai!.TryGetValue(PKS, out int pk) ? pk : null; + int? pkn = row.VotesByKodePartai!.TryGetValue(PKN, out int pn) ? pn : null; + int? hanura = row.VotesByKodePartai!.TryGetValue(HANURA, out int h) ? h : null; + int? garuda = row.VotesByKodePartai!.TryGetValue(GARUDA, out int ga) ? ga : null; + int? pan = row.VotesByKodePartai!.TryGetValue(PAN, out int pa) ? pa : null; + int? pbb = row.VotesByKodePartai!.TryGetValue(PBB, out int pb2) ? pb2 : null; + int? demokrat = row.VotesByKodePartai!.TryGetValue(DEMOKRAT, out int d) ? d : null; + int? psi = row.VotesByKodePartai!.TryGetValue(PSI, out int ps) ? ps : null; + int? perindo = row.VotesByKodePartai!.TryGetValue(PERINDO, out int pe) ? pe : null; + int? ppp = row.VotesByKodePartai!.TryGetValue(PPP, out int pp) ? pp : null; + int? pna = row.VotesByKodePartai!.TryGetValue(PNA, out int pn2) ? pn2 : null; + int? gabthat = row.VotesByKodePartai!.TryGetValue(GABTHAT, out int gab) ? gab : null; + int? pda = row.VotesByKodePartai!.TryGetValue(PDA, out int pd2) ? pd2 : null; + int? partai_aceh = row.VotesByKodePartai!.TryGetValue(PARTAI_ACEH, out int pa2) ? pa2 : null; + int? pas_aceh = row.VotesByKodePartai!.TryGetValue(PAS_ACEH, out int pas) ? pas : null; + int? partai_sira = row.VotesByKodePartai!.TryGetValue(PARTAI_SIRA, out int s) ? s : null; + int? partai_ummat = row.VotesByKodePartai!.TryGetValue(PARTAI_UMMAT, out int u) ? u : null; + int total = (pkb ?? 0) + (gerindra ?? 0) + (pdip ?? 0) + (golkar ?? 0) + (nasdem ?? 0) + (partai_buruh ?? 0) + (gelora ?? 0) + (pks ?? 0) + (pkn ?? 0) + (hanura ?? 0) + (garuda ?? 0) + (pan ?? 0) + (pbb ?? 0) + (demokrat ?? 0) + (psi ?? 0) + (perindo ?? 0) + (ppp ?? 0) + (pna ?? 0) + (gabthat ?? 0) + (pda ?? 0) + (partai_aceh ?? 0) + (pas_aceh ?? 0) + (partai_sira ?? 0) + (partai_ummat ?? 0); + _scopedDatabase.ExecuteNonQuery(""" + INSERT INTO pileg_dpr_dapil (kode_dapil, dapil, progress, pkb, gerindra, pdip, golkar, nasdem, partai_buruh, gelora, pks, pkn, hanura, garuda, pan, pbb, demokrat, psi, perindo, ppp, pna, gabthat, pda, partai_aceh, pas_aceh, partai_sira, partai_ummat, total) + VALUES (@kode_dapil, @dapil, @progress, @pkb, @gerindra, @pdip, @golkar, @nasdem, @partai_buruh, @gelora, @pks, @pkn, @hanura, @garuda, @pan, @pbb, @demokrat, @psi, @perindo, @ppp, @pna, @gabthat, @pda, @partai_aceh, @pas_aceh, @partai_sira, @partai_ummat, @total) + """, + [ + ( "@kode_dapil", kodeDapil ), + ( "@dapil", dapilByKode[kodeDapil].Nama ), + ( "@progress", row.Persen ), + ( "@pkb", pkb), + ( "@gerindra", gerindra), + ( "@pdip", pdip), + ( "@golkar", golkar), + ( "@nasdem", nasdem), + ( "@partai_buruh", partai_buruh), + ( "@gelora", gelora), + ( "@pks", pks), + ( "@pkn", pkn), + ( "@hanura", hanura), + ( "@garuda", garuda), + ( "@pan", pan), + ( "@pbb", pbb), + ( "@demokrat", demokrat), + ( "@psi", psi), + ( "@perindo", perindo), + ( "@ppp", ppp), + ( "@pna", pna), + ( "@gabthat", gabthat), + ( "@pda", pda), + ( "@partai_aceh", partai_aceh), + ( "@pas_aceh", pas_aceh), + ( "@partai_sira", partai_sira), + ( "@partai_ummat", partai_ummat), + ( "@total", total) + ] + ); + } + } + } +} diff --git a/BotNet.Services/Pemilu2024/PilegDPRDataSource.cs b/BotNet.Services/Pemilu2024/PilegDPRPerProvinsiDataSource.cs similarity index 91% rename from BotNet.Services/Pemilu2024/PilegDPRDataSource.cs rename to BotNet.Services/Pemilu2024/PilegDPRPerProvinsiDataSource.cs index be1f956..386e723 100644 --- a/BotNet.Services/Pemilu2024/PilegDPRDataSource.cs +++ b/BotNet.Services/Pemilu2024/PilegDPRPerProvinsiDataSource.cs @@ -6,7 +6,7 @@ using BotNet.Services.Sqlite; namespace BotNet.Services.Pemilu2024 { - public sealed class PilegDPRDataSource( + public sealed class PilegDPRPerProvinsiDataSource( ScopedDatabase scopedDatabase, SirekapClient sirekapClient ) : IScopedDataSource { @@ -39,7 +39,7 @@ SirekapClient sirekapClient public async Task LoadTableAsync(CancellationToken cancellationToken) { _scopedDatabase.ExecuteNonQuery(""" - CREATE TABLE pileg_dpr ( + CREATE TABLE pileg_dpr_provinsi ( provinsi VARCHAR(50) PRIMARY KEY, progress REAL, pkb INTEGER, @@ -75,9 +75,9 @@ total INTEGER keySelector: provinsi => provinsi.Kode ); - ReportPilegDPR report = await _sirekapClient.GetReportPilegDPRAsync(cancellationToken); + ReportPilegDPRByWilayah report = await _sirekapClient.GetReportPilegDPRByProvinsiAsync(cancellationToken); - foreach ((string kodeWilayah, ReportPilegDPR.Row row) in report.RowByKodeWilayah.OrderBy(pair => pair.Key)) { + foreach ((string kodeWilayah, ReportPilegDPRByWilayah.Row row) in report.RowByKodeWilayah.OrderBy(pair => pair.Key)) { int? pkb = row.VotesByKodePartai!.TryGetValue(PKB, out int p) ? p : null; int? gerindra = row.VotesByKodePartai!.TryGetValue(GERINDRA, out int g) ? g : null; int? pdip = row.VotesByKodePartai!.TryGetValue(PDIP, out int pd) ? pd : null; @@ -104,7 +104,7 @@ total INTEGER int? partai_ummat = row.VotesByKodePartai!.TryGetValue(PARTAI_UMMAT, out int u) ? u: null; int total = (pkb ?? 0) + (gerindra ?? 0) + (pdip ?? 0) + (golkar ?? 0) + (nasdem ?? 0) + (partai_buruh ?? 0) + (gelora ?? 0) + (pks ?? 0) + (pkn ?? 0) + (hanura ?? 0) + (garuda ?? 0) + (pan ?? 0) + (pbb ?? 0) + (demokrat ?? 0) + (psi ?? 0) + (perindo ?? 0) + (ppp ?? 0) + (pna ?? 0) + (gabthat ?? 0) + (pda ?? 0) + (partai_aceh ?? 0) + (pas_aceh ?? 0) + (partai_sira ?? 0) + (partai_ummat ?? 0); _scopedDatabase.ExecuteNonQuery(""" - INSERT INTO pileg_dpr (provinsi, progress, pkb, gerindra, pdip, golkar, nasdem, partai_buruh, gelora, pks, pkn, hanura, garuda, pan, pbb, demokrat, psi, perindo, ppp, pna, gabthat, pda, partai_aceh, pas_aceh, partai_sira, partai_ummat, total) + INSERT INTO pileg_dpr_provinsi (provinsi, progress, pkb, gerindra, pdip, golkar, nasdem, partai_buruh, gelora, pks, pkn, hanura, garuda, pan, pbb, demokrat, psi, perindo, ppp, pna, gabthat, pda, partai_aceh, pas_aceh, partai_sira, partai_ummat, total) VALUES (@provinsi, @progress, @pkb, @gerindra, @pdip, @golkar, @nasdem, @partai_buruh, @gelora, @pks, @pkn, @hanura, @garuda, @pan, @pbb, @demokrat, @psi, @perindo, @ppp, @pna, @gabthat, @pda, @partai_aceh, @pas_aceh, @partai_sira, @partai_ummat, @total) """, [ diff --git a/BotNet.Services/Pemilu2024/ServiceCollectionExtensions.cs b/BotNet.Services/Pemilu2024/ServiceCollectionExtensions.cs index 7cbb438..1fd7af0 100644 --- a/BotNet.Services/Pemilu2024/ServiceCollectionExtensions.cs +++ b/BotNet.Services/Pemilu2024/ServiceCollectionExtensions.cs @@ -6,7 +6,8 @@ public static class ServiceCollectionExtensions { public static IServiceCollection AddPemilu2024(this IServiceCollection services) { services.AddTransient(); services.AddKeyedTransient("pilpres"); - services.AddKeyedTransient("pileg_dpr"); + services.AddKeyedTransient("pileg_dpr_provinsi"); + services.AddKeyedTransient("pileg_dpr_dapil"); return services; } } diff --git a/BotNet.Services/Pemilu2024/SirekapClient.cs b/BotNet.Services/Pemilu2024/SirekapClient.cs index cce7410..6e988c2 100644 --- a/BotNet.Services/Pemilu2024/SirekapClient.cs +++ b/BotNet.Services/Pemilu2024/SirekapClient.cs @@ -64,11 +64,18 @@ public async Task GetReportPilpresByWilayahAsync(string kodeWilay ) ?? throw new JsonException("Unexpected response"); } - public async Task GetReportPilegDPRAsync(CancellationToken cancellationToken) { - return await _httpClient.GetFromJsonAsync( + public async Task GetReportPilegDPRByProvinsiAsync(CancellationToken cancellationToken) { + return await _httpClient.GetFromJsonAsync( requestUri: "https://sirekap-obj-data.kpu.go.id/pemilu/hhcw/pdpr.json", cancellationToken: cancellationToken ) ?? throw new JsonException("Unexpected response"); } + + public async Task GetReportPilegDPRByDapilAsync(CancellationToken cancellationToken) { + return await _httpClient.GetFromJsonAsync( + requestUri: "https://sirekap-obj-data.kpu.go.id/pemilu/hhcd/pdpr/0.json", + cancellationToken: cancellationToken + ) ?? throw new JsonException("Unexpected response"); + } } } diff --git a/BotNet.Services/Pemilu2024/Types.cs b/BotNet.Services/Pemilu2024/Types.cs index c5f99e6..d8a8b7e 100644 --- a/BotNet.Services/Pemilu2024/Types.cs +++ b/BotNet.Services/Pemilu2024/Types.cs @@ -68,13 +68,13 @@ int Progres ); } - public sealed record ReportPilegDPR( + public sealed record ReportPilegDPRByWilayah( [property: JsonPropertyName("ts")] string Timestamp, string Psu, string Mode, IDictionary Chart, - [property: JsonPropertyName("table")] IDictionary RowByKodeWilayah, - ReportPilegDPR.Progress Progres + [property: JsonPropertyName("table")] IDictionary RowByKodeWilayah, + ReportPilegDPRByWilayah.Progress Progres ) { public sealed record Row { public string? Psu { get; set; } @@ -91,14 +91,52 @@ public IDictionary? VotesByKodePartai { return null; } - Dictionary votesByKodeCalon = []; + Dictionary votesByKodePartai = []; foreach (KeyValuePair kvp in VotesByKodePartaiJson) { if (kvp.Value.ValueKind == JsonValueKind.Number && kvp.Value.TryGetInt32(out int votes)) { - votesByKodeCalon[kvp.Key] = votes; + votesByKodePartai[kvp.Key] = votes; } } - return votesByKodeCalon; + return votesByKodePartai; + } + } + } + + public sealed record Progress( + int Total, + int Progres + ); + } + + public sealed record ReportPilegDPRByDapil( + [property: JsonPropertyName("ts")] string Timestamp, + string Mode, + IDictionary Chart, + [property: JsonPropertyName("table")] IDictionary RowByKodeDapil, + ReportPilegDPRByDapil.Progress Progres + ) { + public sealed record Row { + public decimal Persen { get; set; } + + [JsonExtensionData] + public IDictionary? VotesByKodePartaiJson { get; set; } + + [JsonIgnore] + public IDictionary? VotesByKodePartai { + get { + if (VotesByKodePartaiJson is null) { + return null; + } + + Dictionary votesByKodePartai = []; + foreach (KeyValuePair kvp in VotesByKodePartaiJson) { + if (kvp.Value.ValueKind == JsonValueKind.Number + && kvp.Value.TryGetInt32(out int votes)) { + votesByKodePartai[kvp.Key] = votes; + } + } + return votesByKodePartai; } } }