128 lines
5.0 KiB
TypeScript
128 lines
5.0 KiB
TypeScript
// prisma/seeds/DemographicsSeeder.ts
|
|
import { PrismaClient } from "@prisma/client";
|
|
|
|
export class DemographicsSeeder {
|
|
constructor(private prisma: PrismaClient) { }
|
|
|
|
async run(): Promise<void> {
|
|
console.log("Seeding demographics data...");
|
|
|
|
// Mendapatkan semua districts
|
|
const districts = await this.prisma.districts.findMany();
|
|
const cities = await this.prisma.cities.findMany();
|
|
|
|
// Seed demografis untuk 6 tahun terakhir
|
|
const currentYear = new Date().getFullYear();
|
|
const years = [currentYear - 5, currentYear - 4, currentYear - 3, currentYear - 2, currentYear - 1, currentYear];
|
|
|
|
// Menghapus data demographics yang sudah ada
|
|
await this.prisma.$executeRaw`TRUNCATE TABLE "demographics" CASCADE`;
|
|
|
|
let counter = 0;
|
|
|
|
// Untuk tiap tahun
|
|
for (const year of years) {
|
|
// Pertama generate data level district
|
|
const districtDemographics = [];
|
|
|
|
for (const district of districts) {
|
|
// Generate data demografis level district
|
|
const districtPopulation = this.getRandomNumber(10000, 100000);
|
|
const districtLandArea = await this.getDistrictLandArea(district.id);
|
|
const districtDensity = districtLandArea > 0
|
|
? districtPopulation / districtLandArea
|
|
: this.getRandomNumber(500, 3000);
|
|
const districtUnemployed = Math.floor(districtPopulation * this.getRandomNumber(0.03, 0.15));
|
|
|
|
// Simpan data district untuk agregasi level kota
|
|
districtDemographics.push({
|
|
district_id: district.id,
|
|
city_id: district.city_id,
|
|
population: districtPopulation,
|
|
unemployed: districtUnemployed,
|
|
density: districtDensity
|
|
});
|
|
|
|
// Simpan data demografis level district
|
|
await this.prisma.demographics.create({
|
|
data: {
|
|
city_id: district.city_id,
|
|
district_id: district.id,
|
|
year,
|
|
population: districtPopulation,
|
|
population_density: districtDensity,
|
|
number_of_unemployed: districtUnemployed
|
|
}
|
|
});
|
|
counter++;
|
|
}
|
|
|
|
// Kemudian generate data level kota berdasarkan agregasi dari district
|
|
for (const city of cities) {
|
|
// Filter district demographics untuk kota ini
|
|
const cityDistricts = districtDemographics.filter(d => d.city_id === city.id);
|
|
|
|
if (cityDistricts.length > 0) {
|
|
// Agregasi data dari semua district dalam kota
|
|
const cityPopulation = cityDistricts.reduce((sum, d) => sum + d.population, 0);
|
|
const cityUnemployed = cityDistricts.reduce((sum, d) => sum + d.unemployed, 0);
|
|
|
|
// Hitung total land area kota
|
|
const cityLandArea = await this.getCityLandArea(city.id);
|
|
|
|
// Hitung kepadatan populasi kota
|
|
const cityDensity = cityLandArea > 0
|
|
? cityPopulation / cityLandArea
|
|
: cityDistricts.reduce((sum, d) => sum + d.density, 0) / cityDistricts.length;
|
|
|
|
// Simpan data demografis level kota
|
|
await this.prisma.demographics.create({
|
|
data: {
|
|
city_id: city.id,
|
|
district_id: cityDistricts[0].district_id, // Menggunakan district pertama sebagai placeholder
|
|
year,
|
|
population: cityPopulation,
|
|
population_density: cityDensity,
|
|
number_of_unemployed: cityUnemployed
|
|
}
|
|
});
|
|
counter++;
|
|
}
|
|
}
|
|
}
|
|
|
|
console.log(`✅ ${counter} demographics records seeded`);
|
|
}
|
|
|
|
private getRandomNumber(min: number, max: number): number {
|
|
return Math.random() * (max - min) + min;
|
|
}
|
|
|
|
private async getDistrictLandArea(districtId: string): Promise<number> {
|
|
const geo = await this.prisma.geographics.findFirst({
|
|
where: { district_id: districtId }
|
|
});
|
|
|
|
return geo?.land_area || 0;
|
|
}
|
|
|
|
private async getCityLandArea(cityId: string): Promise<number> {
|
|
const geo = await this.prisma.geographics.findFirst({
|
|
where: {
|
|
city_id: cityId,
|
|
district_id: null
|
|
}
|
|
});
|
|
|
|
if (geo?.land_area) return geo.land_area;
|
|
|
|
// Jika tidak ada data land area level kota, jumlahkan dari semua district
|
|
const districtsGeo = await this.prisma.geographics.findMany({
|
|
where: { city_id: cityId, district_id: { not: null } }
|
|
});
|
|
|
|
return districtsGeo.reduce((sum, geo) => sum + (geo.land_area || 0), 0);
|
|
}
|
|
}
|
|
|