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;
}
}
}