Kılavuz kodu başka programa devredildiğinde (ör. 209210292: Diş Hekimliği SAY lisans → İlk ve Acil Yardım TYT önlisans) refresh yalnız koda bakıp yıl kolonlarını yazıyordu; satır eski adıyla yeni programın sırasını gösteriyordu. - scripts/kimlik.ts (yeni): kimlik = puan türü + önlisans + baz ad slug'ı. Devir yılı kanıt zinciriyle bulunur (API …1/…2/…3 sıra/puanı DB ile eşleşen ardışık yıllar + netler.puanTuru); API geçmişi kod bazlı ve kirli olduğu için (gk2, bazı basariSirasi3) zincirsiz güvenilmez. Yalnız adı değişen ve API penceresinin tamamında sürekliliği olan satır "ad değişimi"dir, geçmişi korunur. - refresh: uyumsuz satır varsa listeler ve HİÇBİR ŞEY yazmadan durur; --kimlik-onar ile isim/tur/onlisans/fakulte/sure API'den yazılır, devir öncesi tüm yıl kolonları NULL'lanır, eski kimlik + geçmişi programs_arsiv'e <kod>~<yıl> id'siyle kopyalanır, eski yılların netleri oraya taşınır, veri_meta'ya kimlik_onar:<kod> kaydı düşer. Önceki-yıl sağlaması onarılanlar dışındaki satırlar için aynen geçerli. --isim-esitle (varsayılan kapalı): kimliği aynı, yalnız burs/dil eki farklı satırlarda isim API'den. - gecmis-doldur: onarılmış satırda devir öncesi yılları hiçbir kaynaktan doldurmaz (yoksa API'nin kod bazlı …N alanları eski programı geri yazar). - veri-kalite: --ham ile ZORUNLU kimlik kontrolü (0 uyumsuz beklenir); --onceki karşılaştırmasında onarılanlar ayrı doğrulanır. - docs/veri/yillik-guncelleme.md: kimlik kilidi adımı. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
300 lines
17 KiB
TypeScript
300 lines
17 KiB
TypeScript
/**
|
||
* yokatlas.db veri kalitesi denetimi — SALT OKUNUR. Yayın öncesi kapı:
|
||
* bir ZORUNLU kontrol başarısızsa çıkış kodu 1 (CI/runbook durur).
|
||
* UYARI'lar çıkış kodunu etkilemez; insan gözüyle bakılır.
|
||
*
|
||
* Kullanım:
|
||
* pnpm veri-kalite --yil 2026 --db /tmp/deneme.db [--onceki data/yokatlas.db] [--arsivli] [--ham <dosya>]
|
||
*
|
||
* --ham <dosya> Ham API çekimi (yoksa data/ham altındaki en yenisi). Verilirse
|
||
* KİMLİK kontrolü koşar: her DB satırının puan türü / önlisans /
|
||
* baz ad slug'ı aynı koddaki API kaydıyla uyuşmalı (0 beklenir;
|
||
* uyuşmayan = kılavuz kodu başka programa devredilmiş, satır eski
|
||
* adıyla yeni programın sırasını gösteriyor → refresh --kimlik-onar).
|
||
* --onceki <db> Güncelleme ÖNCESİ DB. Verilirse: iki DB'de de bulunan her
|
||
* programın önceki yıl kolonları (sira/puan/kontenjan/yerlesen)
|
||
* birebir aynı mı (dolu değer değişmiş/silinmiş olamaz).
|
||
* --arsivli programs içinde güncel kılavuzda olmayan satır kalmamış olmalı.
|
||
*/
|
||
import path from "node:path";
|
||
import { EFEKTIF_SIRA_SQL, ILK_YIL } from "../src/lib/veri-yillari";
|
||
import { EFEKTIF_INDEKS, efektifSorguPlani } from "./db-index";
|
||
import { kimlikFarklari, onarimKayitlari, yilKolonlari, type DbKimlik } from "./kimlik";
|
||
import { hamOku, sonHamDosya, TUR_MAP } from "./refresh";
|
||
import {
|
||
argOku,
|
||
bayrakVar,
|
||
calistir,
|
||
dbAc,
|
||
dbArgumani,
|
||
dur,
|
||
kolonAdlari,
|
||
metaOku,
|
||
tabloVar,
|
||
yilArgumani,
|
||
} from "./yokatlas-goc";
|
||
|
||
const TURLER = ["SAYISAL", "EŞİT AĞIRLIK", "SÖZEL", "DİL", "TYT"];
|
||
|
||
async function main() {
|
||
const yil = yilArgumani();
|
||
const dbYolu = dbArgumani();
|
||
const oncekiArg = argOku("onceki");
|
||
const arsivli = bayrakVar("arsivli");
|
||
const db = dbAc(dbYolu, { saltOkunur: true });
|
||
const onceki = yil - 1;
|
||
|
||
let basarisiz = 0;
|
||
let uyari = 0;
|
||
const zorunlu = (ad: string, tamam: boolean, detay: string) => {
|
||
console.log(`${tamam ? "GEÇTİ " : "KALDI "} ${ad} — ${detay}`);
|
||
if (!tamam) basarisiz++;
|
||
};
|
||
const bilgi = (ad: string, sorunlu: boolean, detay: string) => {
|
||
console.log(`${sorunlu ? "UYARI " : "bilgi "} ${ad} — ${detay}`);
|
||
if (sorunlu) uyari++;
|
||
};
|
||
const sayi = (sql: string, ...args: unknown[]) =>
|
||
(db.prepare(sql).get(...args) as { n: number }).n;
|
||
const ornek = (sql: string, ...args: unknown[]) =>
|
||
(db.prepare(sql).raw().all(...args) as unknown[][]).map((r) => r.join("/")).join(" ; ");
|
||
|
||
console.log(`DB: ${dbYolu}\nYıl: ${yil} Efektif sıra: ${EFEKTIF_SIRA_SQL}\n`);
|
||
|
||
// 1. Dosya bütünlüğü
|
||
const butunluk = (db.pragma("integrity_check") as { integrity_check: string }[])
|
||
.map((r) => r.integrity_check)
|
||
.join(",");
|
||
zorunlu("integrity_check", butunluk === "ok", butunluk);
|
||
|
||
// 2. Şema
|
||
const kolonlar = new Set(kolonAdlari(db, "programs"));
|
||
const gerekli = [`sira${yil}`, `puan${yil}`, `kontenjan${yil}`, `yerlesen${yil}`, "son_kilavuz_yili", "eski_kod"];
|
||
const eksikKolon = gerekli.filter((k) => !kolonlar.has(k));
|
||
zorunlu("şema", eksikKolon.length === 0, eksikKolon.length ? `eksik: ${eksikKolon.join(", ")}` : "yıl kolonları + son_kilavuz_yili + eski_kod var");
|
||
if (eksikKolon.length) {
|
||
dur("Şema eksik; kalan kontroller koşulamaz.");
|
||
}
|
||
|
||
// 3. Kapsam: güncel satır = API toplamı − atlanan
|
||
const apiToplam = Number(metaOku(db, `refresh_${yil}_api_toplam`) ?? NaN);
|
||
const atlanan = Number(metaOku(db, `refresh_${yil}_atlanan`) ?? NaN);
|
||
const guncel = sayi("SELECT COUNT(*) AS n FROM programs WHERE son_kilavuz_yili = ?", yil);
|
||
zorunlu(
|
||
"kapsam",
|
||
Number.isFinite(apiToplam) && guncel === apiToplam - atlanan,
|
||
`son_kilavuz_yili=${yil}: ${guncel}; API toplamı ${apiToplam} − atlanan ${atlanan} = ${apiToplam - atlanan}`
|
||
);
|
||
|
||
// 4. Doluluk
|
||
const sirali = sayi(`SELECT COUNT(sira${yil}) AS n FROM programs WHERE son_kilavuz_yili = ?`, yil);
|
||
const oncekiSirali = sayi(`SELECT COUNT(sira${onceki}) AS n FROM programs WHERE son_kilavuz_yili = ?`, yil);
|
||
const doluOran = guncel ? sirali / guncel : 0;
|
||
zorunlu(
|
||
`sira${yil} doluluk`,
|
||
doluOran >= 0.7,
|
||
`${sirali}/${guncel} (%${(doluOran * 100).toFixed(1)}; eşik %70). Aynı satırlarda sira${onceki} dolu: ${oncekiSirali}`
|
||
);
|
||
const puanli = sayi(`SELECT COUNT(puan${yil}) AS n FROM programs WHERE son_kilavuz_yili = ?`, yil);
|
||
const kontenjanli = sayi(`SELECT COUNT(kontenjan${yil}) AS n FROM programs WHERE son_kilavuz_yili = ?`, yil);
|
||
bilgi(`${yil} diğer ölçüler`, kontenjanli < guncel * 0.95, `puan dolu ${puanli}, kontenjan dolu ${kontenjanli}, toplam ${guncel}`);
|
||
|
||
// 5. Yıllar arası tutarlılık: sira Y / sira Y-1 ∈ [0,5; 2]
|
||
const ikisiDolu = sayi(`SELECT COUNT(*) AS n FROM programs WHERE sira${yil} IS NOT NULL AND sira${onceki} IS NOT NULL`);
|
||
const aralikta = sayi(
|
||
`SELECT COUNT(*) AS n FROM programs WHERE sira${yil} IS NOT NULL AND sira${onceki} IS NOT NULL
|
||
AND sira${yil} * 1.0 / sira${onceki} BETWEEN 0.5 AND 2`
|
||
);
|
||
const aralikOran = ikisiDolu ? aralikta / ikisiDolu : 0;
|
||
zorunlu(
|
||
`sira${yil}/sira${onceki} ∈ [0,5; 2]`,
|
||
ikisiDolu > 0 && aralikOran >= 0.9,
|
||
`${aralikta}/${ikisiDolu} (%${(aralikOran * 100).toFixed(1)}; eşik %90)`
|
||
);
|
||
const ayniSira = sayi(
|
||
`SELECT COUNT(*) AS n FROM programs WHERE sira${yil} IS NOT NULL AND sira${yil} = sira${onceki} AND puan${yil} = puan${onceki}`
|
||
);
|
||
zorunlu(
|
||
"yıl kayması (kopya yıl)",
|
||
ikisiDolu > 0 && ayniSira / ikisiDolu < 0.02,
|
||
`sıra VE puanı ${onceki} ile birebir aynı satır: ${ayniSira}/${ikisiDolu} (çoksa ${yil} kolonuna ${onceki} verisi yazılmıştır)`
|
||
);
|
||
|
||
// 6. Değer aralıkları (tüm yıllar)
|
||
const yillar: number[] = [];
|
||
for (let y = ILK_YIL; y <= yil; y++) if (kolonlar.has(`sira${y}`)) yillar.push(y);
|
||
const bozukKosul = yillar
|
||
.map((y) => `sira${y} <= 0 OR sira${y} > 5000000 OR puan${y} <= 0 OR puan${y} > 600 OR kontenjan${y} < 0 OR yerlesen${y} < 0`)
|
||
.join(" OR ");
|
||
const bozuk = sayi(`SELECT COUNT(*) AS n FROM programs WHERE ${bozukKosul}`);
|
||
zorunlu("değer aralığı", bozuk === 0, `0/negatif/aşırı sıra-puan-kontenjan: ${bozuk}${bozuk ? ` ör. ${ornek(`SELECT id FROM programs WHERE ${bozukKosul} LIMIT 3`)}` : ""}`);
|
||
|
||
const siraPuanTutarsiz = sayi(
|
||
`SELECT COUNT(*) AS n FROM programs WHERE sira${yil} IS NOT NULL AND puan${yil} IS NULL`
|
||
);
|
||
zorunlu(`sira${yil} var, puan${yil} yok`, siraPuanTutarsiz === 0, `${siraPuanTutarsiz} satır`);
|
||
|
||
// 7. Kategorik alanlar
|
||
const bozukTur = sayi(
|
||
`SELECT COUNT(*) AS n FROM programs WHERE tur NOT IN (${TURLER.map(() => "?").join(",")}) OR onlisans NOT IN (0, 1)`,
|
||
...TURLER
|
||
);
|
||
zorunlu("tur/onlisans", bozukTur === 0, `geçersiz değer: ${bozukTur}`);
|
||
const tytTutarsiz = sayi("SELECT COUNT(*) AS n FROM programs WHERE (tur = 'TYT') <> (onlisans = 1) AND son_kilavuz_yili = ?", yil);
|
||
bilgi("TYT ↔ önlisans", tytTutarsiz > 0, `tur=TYT ile onlisans=1 örtüşmeyen güncel satır: ${tytTutarsiz}${tytTutarsiz ? ` ör. ${ornek("SELECT id, tur, onlisans FROM programs WHERE (tur = 'TYT') <> (onlisans = 1) AND son_kilavuz_yili = ? LIMIT 3", yil)}` : ""}`);
|
||
const uniturBos = sayi("SELECT COUNT(*) AS n FROM programs WHERE unitur IS NULL AND son_kilavuz_yili = ?", yil);
|
||
bilgi("unitur boş", uniturBos > 0, `güncel satırlarda ${uniturBos} (devlet/vakıf filtresinden düşer)${uniturBos ? ` ör. ${ornek("SELECT DISTINCT universite FROM programs WHERE unitur IS NULL AND son_kilavuz_yili = ? LIMIT 3", yil)}` : ""}`);
|
||
const uniturlar = ornek("SELECT COALESCE(unitur, '(NULL)'), COUNT(*) FROM programs GROUP BY unitur ORDER BY 2 DESC");
|
||
bilgi("unitur dağılımı", false, uniturlar);
|
||
const ilBos = sayi("SELECT COUNT(*) AS n FROM programs WHERE (il IS NULL OR TRIM(il) = '') AND son_kilavuz_yili = ?", yil);
|
||
bilgi("il boş", ilBos > 0, `güncel satırlarda ${ilBos}${ilBos ? ` ör. ${ornek("SELECT id, universite FROM programs WHERE (il IS NULL OR TRIM(il) = '') AND son_kilavuz_yili = ? LIMIT 3", yil)}` : ""}`);
|
||
|
||
// 8. Kontenjan–yerleşen
|
||
const tasan = sayi(`SELECT COUNT(*) AS n FROM programs WHERE yerlesen${yil} > kontenjan${yil} * 1.5 + 5`);
|
||
bilgi(`yerlesen${yil} ≫ kontenjan${yil}`, tasan > guncel * 0.02, `yerleşen > 1,5×genel kontenjan + 5: ${tasan} (yerleşen okul birincisi/şehit-gazi/deprem kontenjanlarını da içerir)${tasan ? ` ör. ${ornek(`SELECT id, kontenjan${yil}, yerlesen${yil} FROM programs WHERE yerlesen${yil} > kontenjan${yil} * 1.5 + 5 LIMIT 3`)}` : ""}`);
|
||
const doluAmaSirasiz = sayi(`SELECT COUNT(*) AS n FROM programs WHERE son_kilavuz_yili = ? AND sira${yil} IS NULL AND yerlesen${yil} > 0`, yil);
|
||
bilgi(`yerleşen var, sira${yil} yok`, false, `${doluAmaSirasiz} (API az yerleşenli programda sıra vermez; efektif sıra ${onceki}'e düşer)`);
|
||
|
||
// 9. Eski/çift satırlar
|
||
const eskiSatir = sayi("SELECT COUNT(*) AS n FROM programs WHERE son_kilavuz_yili IS NOT ?", yil);
|
||
if (arsivli) zorunlu("arşiv", eskiSatir === 0, `programs içinde güncel kılavuzda olmayan satır: ${eskiSatir}`);
|
||
else bilgi("arşivlenmemiş eski satır", eskiSatir > 0, `${eskiSatir} satır güncel kılavuzda yok ama sitede listelenir (efektif sıra ${onceki}'e düşer)`);
|
||
const ciftAd = sayi(
|
||
`SELECT COUNT(*) AS n FROM (SELECT 1 FROM programs WHERE son_kilavuz_yili = ?
|
||
GROUP BY universite, fakulte, isim, tur HAVING COUNT(*) > 1)`,
|
||
yil
|
||
);
|
||
bilgi("aynı adlı güncel program", false, `(universite, fakulte, isim, tur) yinelenen grup: ${ciftAd} (özel kontenjanlı adaş programlar olağandır)${ciftAd ? ` ör. ${ornek("SELECT universite, isim, COUNT(*) FROM programs WHERE son_kilavuz_yili = ? GROUP BY universite, fakulte, isim, tur HAVING COUNT(*) > 1 LIMIT 3", yil)}` : ""}`);
|
||
const eskiKodCakisma = sayi(
|
||
"SELECT COUNT(*) AS n FROM (SELECT eski_kod FROM programs WHERE eski_kod IS NOT NULL AND son_kilavuz_yili = ? GROUP BY eski_kod HAVING COUNT(*) > 1)",
|
||
yil
|
||
);
|
||
bilgi("eski_kod paylaşımı (bölünme)", eskiKodCakisma > 0, `birden çok güncel programın işaret ettiği eski kod: ${eskiKodCakisma}`);
|
||
|
||
// 9b. Kimlik: kod aynı, program aynı mı? (ham çekim gerekir)
|
||
const hamArg = argOku("ham");
|
||
const hamDosya = hamArg
|
||
? path.resolve(process.cwd(), hamArg)
|
||
: sonHamDosya(yil, path.resolve(process.cwd(), "data", "ham"));
|
||
const onarimlar = onarimKayitlari(db);
|
||
if (hamDosya) {
|
||
const { kayitlar } = await hamOku(hamDosya, yil);
|
||
const getir = db.prepare("SELECT id, isim, tur, onlisans, fakulte, sure, universite FROM programs WHERE id = ?");
|
||
const uyumsuz: string[] = [];
|
||
let kiyaslanan = 0;
|
||
let ekFarki = 0;
|
||
for (const r of kayitlar) {
|
||
if (!r.kilavuzKodu) continue;
|
||
const satir = getir.get(String(r.kilavuzKodu)) as (DbKimlik & { universite: string }) | undefined;
|
||
if (!satir) continue;
|
||
kiyaslanan++;
|
||
const farklar = kimlikFarklari(satir, r, TUR_MAP[r.puanTuru?.trim() ?? ""]);
|
||
if (farklar.length) {
|
||
uyumsuz.push(`${satir.id}[${farklar.join("+")}] DB="${satir.isim}"/${satir.tur}/${satir.onlisans} API="${r.birimAdi}"/${r.puanTuru}/${r.birimTuruId === 47 ? 1 : 0} (${satir.universite})`);
|
||
} else if (satir.isim !== r.birimAdi) {
|
||
ekFarki++;
|
||
}
|
||
}
|
||
zorunlu(
|
||
"kimlik (tur/önlisans/baz ad = API)",
|
||
uyumsuz.length === 0,
|
||
`${kiyaslanan} satır kıyaslandı, uyumsuz: ${uyumsuz.length}${uyumsuz.length ? ` ör. ${uyumsuz.slice(0, 3).join(" ; ")}` : ""} [${path.basename(hamDosya)}]`
|
||
);
|
||
bilgi("isim eki (burs/dil) API'den farklı", false, `${ekFarki} satır — kimlik aynı, DB adı eksiz/farklı yazımlı (aynı üniversitede adaş varyantlar ayırt edilemez)`);
|
||
} else {
|
||
bilgi("kimlik", true, "ATLANDI: --ham verilmedi ve data/ham altında çekim yok; kod devri denetlenemedi");
|
||
}
|
||
if (onarimlar.size) {
|
||
// Onarılan satırda devir öncesi hiçbir yıl kolonu dolu kalmış olamaz.
|
||
const yk = yilKolonlari(db);
|
||
let sizinti = 0;
|
||
const satirGetir = db.prepare("SELECT * FROM programs WHERE id = ?");
|
||
for (const [id, k] of onarimlar) {
|
||
const s = satirGetir.get(id) as Record<string, unknown> | undefined;
|
||
if (!s) continue;
|
||
if (yk.some((c) => c.yil < k.devirYili && s[c.kolon] != null)) sizinti++;
|
||
}
|
||
zorunlu("kimliği onarılanlar: devir öncesi boş", sizinti === 0, `${onarimlar.size} onarılmış satırın ${sizinti} tanesinde devir öncesi yıl yeniden dolmuş`);
|
||
}
|
||
|
||
// 10. netler
|
||
if (tabloVar(db, "netler")) {
|
||
const arsivVar = tabloVar(db, "programs_arsiv");
|
||
const yetim = sayi(
|
||
`SELECT COUNT(*) AS n FROM netler WHERE program_id NOT IN (SELECT id FROM programs)
|
||
${arsivVar ? "AND program_id NOT IN (SELECT id FROM programs_arsiv)" : ""}`
|
||
);
|
||
bilgi("yetim netler", yetim > 0, `ne programs ne arşivde karşılığı olan: ${yetim}`);
|
||
const netliGuncel = sayi(
|
||
"SELECT COUNT(DISTINCT n.program_id) AS n FROM netler n JOIN programs p ON p.id = n.program_id WHERE p.son_kilavuz_yili = ?",
|
||
yil
|
||
);
|
||
bilgi("netler kapsamı", false, `net satırı olan güncel program: ${netliGuncel}/${guncel}; yıl dağılımı: ${ornek("SELECT yil, COUNT(*) FROM netler GROUP BY yil ORDER BY yil")}`);
|
||
}
|
||
|
||
// 11. Sorgu planı
|
||
const plan = efektifSorguPlani(db);
|
||
zorunlu("sorgu planı", plan.some((s) => s.includes(EFEKTIF_INDEKS)), plan.join(" | "));
|
||
|
||
// 12. Önceki DB ile geçmiş yıl karşılaştırması
|
||
if (oncekiArg) {
|
||
const oncekiYol = path.resolve(process.cwd(), oncekiArg);
|
||
db.prepare("ATTACH DATABASE ? AS eski").run(oncekiYol);
|
||
const eskiKolonlar = new Set(
|
||
(db.prepare("PRAGMA eski.table_info(programs)").all() as { name: string }[]).map((c) => c.name)
|
||
);
|
||
const ortak: string[] = [];
|
||
for (let y = ILK_YIL; y < yil; y++) {
|
||
for (const o of ["sira", "puan", "kontenjan", "yerlesen"]) {
|
||
if (kolonlar.has(`${o}${y}`) && eskiKolonlar.has(`${o}${y}`)) ortak.push(`${o}${y}`);
|
||
}
|
||
}
|
||
const simdi = tabloVar(db, "programs_arsiv")
|
||
? `(SELECT id, ${ortak.join(", ")} FROM main.programs UNION ALL SELECT id, ${ortak.join(", ")} FROM main.programs_arsiv)`
|
||
: "main.programs";
|
||
const kaybolan = sayi(`SELECT COUNT(*) AS n FROM eski.programs e WHERE e.id NOT IN (SELECT id FROM ${simdi})`);
|
||
zorunlu("önceki DB: satır kaybı", kaybolan === 0, `önceki DB'de olup şimdi ne programs ne arşivde olan: ${kaybolan}`);
|
||
// Dolu değer değişmiş ya da NULL'a dönmüş olamaz; NULL → dolu (gecmis-doldur) serbest.
|
||
// Kimliği onarılan satırlarda devir öncesi yıllar BİLEREK NULL'landı; onlar
|
||
// ayrı sayılır: devir yılı ve sonrası yine birebir korunmuş olmalı.
|
||
const onarilanJson = JSON.stringify([...onarimlar.keys()]);
|
||
const degisen = sayi(
|
||
`SELECT COUNT(*) AS n FROM eski.programs e JOIN ${simdi} s ON s.id = e.id
|
||
WHERE e.id NOT IN (SELECT value FROM json_each(?))
|
||
AND (${ortak.map((k) => `(e.${k} IS NOT NULL AND e.${k} IS NOT s.${k})`).join(" OR ")})`,
|
||
onarilanJson
|
||
);
|
||
zorunlu("önceki DB: geçmiş yıllar korunmuş", degisen === 0, `${ortak.length} kolonda dolu değeri değişen/silinen satır: ${degisen} (kimliği onarılan ${onarimlar.size} satır hariç)`);
|
||
if (onarimlar.size) {
|
||
let bozulan = 0;
|
||
const eskiGetir = db.prepare("SELECT * FROM eski.programs WHERE id = ?");
|
||
const yeniGetir = db.prepare("SELECT * FROM main.programs WHERE id = ?");
|
||
for (const [id, k] of onarimlar) {
|
||
const e = eskiGetir.get(id) as Record<string, unknown> | undefined;
|
||
const s = yeniGetir.get(id) as Record<string, unknown> | undefined;
|
||
if (!e || !s) continue;
|
||
const korunmali = ortak.filter((kolon) => Number(kolon.slice(-4)) >= k.devirYili);
|
||
if (korunmali.some((kolon) => e[kolon] != null && e[kolon] !== s[kolon])) bozulan++;
|
||
}
|
||
zorunlu("önceki DB: onarılanlarda devir sonrası korunmuş", bozulan === 0, `devir yılı ve sonrasında değeri değişen onarılmış satır: ${bozulan}/${onarimlar.size}`);
|
||
}
|
||
const toplamlar = (tablo: string) =>
|
||
(db
|
||
.prepare(
|
||
`SELECT COUNT(*), TOTAL(sira${onceki}), TOTAL(puan${onceki}), TOTAL(kontenjan${onceki}), TOTAL(yerlesen${onceki}) FROM ${tablo}`
|
||
)
|
||
.raw()
|
||
.get() as number[]).join(" | ");
|
||
console.log(` ${onceki} sağlaması (count | Σsira | Σpuan | Σkontenjan | Σyerlesen)`);
|
||
console.log(` önceki DB : ${toplamlar("eski.programs")}`);
|
||
console.log(` şimdi, önceki DB'deki aynı id'ler : ${toplamlar(`${simdi} WHERE id IN (SELECT id FROM eski.programs)`)}`);
|
||
console.log(` şimdi, tüm satırlar (yeni dahil) : ${toplamlar(simdi)}`);
|
||
}
|
||
|
||
db.close();
|
||
console.log(`\nSonuç: ${basarisiz} ZORUNLU kontrol kaldı, ${uyari} uyarı.`);
|
||
if (basarisiz > 0) process.exit(1);
|
||
}
|
||
|
||
if (process.argv[1]?.endsWith("veri-kalite.ts")) calistir(main);
|