scripts/program-ozellik.ts (pnpm ozellik --yil --db [--ham]) API'nin kılavuz alanlarını program_ozellik ve kosul tablolarına yazar; 25 Eyl 2026 çekimi: 21.493 program, 194 koşul metni. src/lib/program-ozellik.ts okuyucu + öğrenciye okunan kısa özet. Tablo yoksa okuma boş döner. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
138 lines
5.0 KiB
TypeScript
138 lines
5.0 KiB
TypeScript
// Program özellikleri: YÖK Atlas API'sinden scripts/program-ozellik.ts ile
|
||
// `program_ozellik` ve `kosul` tablolarına yazılan, yıl anlamı olmayan alanlar
|
||
// (ücret, burs, dil, öğretim türü, akreditasyon, kadro, baraj, ilçe, koşullar).
|
||
// Sıra/puan/kontenjan gibi yıllık alanlar burada DEĞİL (bkz. db.ts).
|
||
import { getDb } from "./db";
|
||
|
||
export type ProgramOzellik = {
|
||
id: string;
|
||
/** Vakıf/KKTC yıllık öğrenim ücreti (TL, KDV dahil, kılavuz yılı); devlette null */
|
||
ucret: number | null;
|
||
/** "Burslu" | "%50 İndirimli" | "%25 İndirimli" | "Ücretli"; devlette null */
|
||
bursOrani: string | null;
|
||
/** "Türkçe" | "İngilizce" | "İngilizce (%30)" | "Almanca" … */
|
||
ogrenimDili: string | null;
|
||
/** "Örgün Öğretim" | "Uzaktan Öğretim" | "Açık Öğretim" | "UOLP" */
|
||
ogrenimTuru: string | null;
|
||
/** Program akreditasyonu (MÜDEK, TEPDAD, FEDEK …) */
|
||
akreditasyon: string | null;
|
||
/** Üniversite akreditasyonu (YÖKAK …) */
|
||
uniAkreditasyon: string | null;
|
||
prof: number | null;
|
||
doc: number | null;
|
||
dou: number | null;
|
||
argor: number | null;
|
||
/** Tercih edebilmek için gereken en düşük başarı sırası (baraj) */
|
||
minBasariSirasi: number | null;
|
||
/** Kampüs ilçesi (büyük harf, API'den) */
|
||
ilce: string | null;
|
||
/** Yerleşme koşulu kodları (kosul tablosundan metne çevrilir) */
|
||
kosulKodlari: string[];
|
||
/** Kılavuz yılı */
|
||
yil: number;
|
||
};
|
||
|
||
type HamSatir = {
|
||
id: string;
|
||
ucret: number | null;
|
||
burs_orani: string | null;
|
||
ogrenim_dili: string | null;
|
||
ogrenim_turu: string | null;
|
||
akreditasyon: string | null;
|
||
uni_akreditasyon: string | null;
|
||
prof: number | null;
|
||
doc: number | null;
|
||
dou: number | null;
|
||
argor: number | null;
|
||
min_basari_sirasi: number | null;
|
||
ilce: string | null;
|
||
kosul_kodlari: string | null;
|
||
yil: number;
|
||
};
|
||
|
||
const OZELLIK_COLS = `id, ucret, burs_orani, ogrenim_dili, ogrenim_turu, akreditasyon,
|
||
uni_akreditasyon, prof, doc, dou, argor, min_basari_sirasi, ilce, kosul_kodlari, yil`;
|
||
|
||
function satir(r: HamSatir): ProgramOzellik {
|
||
return {
|
||
id: r.id,
|
||
ucret: r.ucret,
|
||
bursOrani: r.burs_orani,
|
||
ogrenimDili: r.ogrenim_dili,
|
||
ogrenimTuru: r.ogrenim_turu,
|
||
akreditasyon: r.akreditasyon,
|
||
uniAkreditasyon: r.uni_akreditasyon,
|
||
prof: r.prof,
|
||
doc: r.doc,
|
||
dou: r.dou,
|
||
argor: r.argor,
|
||
minBasariSirasi: r.min_basari_sirasi,
|
||
ilce: r.ilce,
|
||
kosulKodlari: r.kosul_kodlari ? r.kosul_kodlari.split(",") : [],
|
||
yil: r.yil,
|
||
};
|
||
}
|
||
|
||
/** Tablo yoksa (eski DB) her okuma null/boş döner; sayfa kırılmaz. */
|
||
function tabloVar(): boolean {
|
||
return (
|
||
getDb()
|
||
.prepare("SELECT 1 FROM sqlite_master WHERE type='table' AND name='program_ozellik'")
|
||
.get() !== undefined
|
||
);
|
||
}
|
||
|
||
export function programOzellikGetir(id: string): ProgramOzellik | null {
|
||
if (!tabloVar()) return null;
|
||
const r = getDb()
|
||
.prepare(`SELECT ${OZELLIK_COLS} FROM program_ozellik WHERE id = ?`)
|
||
.get(id) as HamSatir | undefined;
|
||
return r ? satir(r) : null;
|
||
}
|
||
|
||
export function programOzellikleriGetir(
|
||
ids: readonly string[]
|
||
): Record<string, ProgramOzellik> {
|
||
const sonuc: Record<string, ProgramOzellik> = {};
|
||
if (ids.length === 0 || !tabloVar()) return sonuc;
|
||
const satirlar = getDb()
|
||
.prepare(
|
||
`SELECT ${OZELLIK_COLS} FROM program_ozellik WHERE id IN (${ids.map(() => "?").join(",")})`
|
||
)
|
||
.all(...ids) as HamSatir[];
|
||
for (const r of satirlar) sonuc[r.id] = satir(r);
|
||
return sonuc;
|
||
}
|
||
|
||
/** Koşul kodlarının kılavuz metinleri, kod sırasıyla. Bilinmeyen kod atlanır. */
|
||
export function kosulMetinleri(kodlar: readonly string[]): { kod: string; metin: string }[] {
|
||
if (kodlar.length === 0 || !tabloVar()) return [];
|
||
const satirlar = getDb()
|
||
.prepare(`SELECT kod, metin FROM kosul WHERE kod IN (${kodlar.map(() => "?").join(",")})`)
|
||
.all(...kodlar) as { kod: string; metin: string }[];
|
||
const harita = new Map(satirlar.map((s) => [s.kod, s.metin]));
|
||
return kodlar.flatMap((k) => (harita.has(k) ? [{ kod: k, metin: harita.get(k)! }] : []));
|
||
}
|
||
|
||
/** Kadro toplamı (prof + doç + dr. öğr. üyesi); hiçbiri yoksa null. */
|
||
export function ogretimUyesiToplami(o: ProgramOzellik): number | null {
|
||
const parcalar = [o.prof, o.doc, o.dou].filter((x): x is number => x != null);
|
||
return parcalar.length ? parcalar.reduce((a, b) => a + b, 0) : null;
|
||
}
|
||
|
||
/** Öğrenciye okunan kısa özet: "İngilizce · Burslu · MÜDEK akreditasyonlu". */
|
||
export function ozellikOzeti(o: ProgramOzellik): string[] {
|
||
const parcalar: string[] = [];
|
||
if (o.ogrenimDili && o.ogrenimDili !== "Türkçe") parcalar.push(o.ogrenimDili);
|
||
if (o.ogrenimTuru && o.ogrenimTuru !== "Örgün Öğretim") parcalar.push(o.ogrenimTuru);
|
||
if (o.bursOrani) parcalar.push(o.bursOrani);
|
||
if (o.ucret != null && o.bursOrani !== "Burslu") {
|
||
parcalar.push(`yıllık ${o.ucret.toLocaleString("tr-TR")} TL`);
|
||
}
|
||
if (o.akreditasyon) parcalar.push(`${o.akreditasyon} akreditasyonlu`);
|
||
if (o.minBasariSirasi != null) {
|
||
parcalar.push(`baraj ${o.minBasariSirasi.toLocaleString("tr-TR")}. sıra`);
|
||
}
|
||
return parcalar;
|
||
}
|