jws-backend/src/utils/thailand-area.ts
2024-11-25 14:32:49 +07:00

236 lines
7.7 KiB
TypeScript

import { parseFile } from "@fast-csv/parse";
import prisma from "../db";
export async function initThailandAreaDatabase() {
const data = await new Promise<Record<string, string>[]>((resolve, reject) => {
const r: Record<string, string>[] = [];
const stream = parseFile("./assets/thailand-area.csv", { headers: true });
stream.on("data", (v) => r.push(v));
stream.on("error", (e) => reject(e));
stream.on("end", () => resolve(r));
}).catch((e) => console.error(e));
if (!data) return;
type Base = { id: string; name: string; nameEN: string };
const province: Base[] = [];
const district: (Base & { provinceId: string })[] = [];
const subDistrict: (Base & { zipCode: string; districtId: string })[] = [];
data.forEach((record) => {
const provinceId = record["TambonID"].slice(0, 2);
const districtId = record["TambonID"].slice(0, 4);
const subDistrictId = record["TambonID"];
if (!province.find((v) => v.id === provinceId)) {
province.push({
id: provinceId,
name: record["ProvinceThai"],
nameEN: record["ProvinceEng"],
});
}
if (!district.find((v) => v.id === districtId)) {
district.push({
id: districtId,
name: record["DistrictThaiShort"],
nameEN: record["DistrictEngShort"],
provinceId,
});
}
if (!subDistrict.find((v) => v.id === subDistrictId)) {
subDistrict.push({
id: subDistrictId,
name: record["TambonThaiShort"],
nameEN: record["TambonEngShort"],
zipCode: record["PostCodeMain"],
districtId,
});
}
});
function splitChunk<DataType, ResponseType>(
array: DataType[],
chunkSize: number,
callback: (data: DataType[]) => ResponseType,
) {
const result: ReturnType<typeof callback>[] = [];
for (let i = 0; i < array.length; i += chunkSize) {
result.push(callback(array.slice(i, i + chunkSize)));
}
return result;
}
await prisma.$transaction(async (tx) => {
const meta = {
createdBy: null,
createdAt: new Date(),
updatedBy: null,
updatedAt: new Date(),
};
await Promise.all(
splitChunk(province, 1000, async (r) => {
return await tx.$kysely
.insertInto("Province")
.columns(["id", "name", "nameEN", "createdBy", "createdAt", "updatedBy", "updatedAt"])
.values(r.map((v) => ({ ...v, ...meta })))
.onConflict((oc) =>
oc.column("id").doUpdateSet({
name: (eb) => eb.ref("excluded.name"),
nameEN: (eb) => eb.ref("excluded.nameEN"),
updatedAt: (eb) => eb.ref("excluded.updatedAt"),
}),
)
.execute();
}),
);
await Promise.all(
splitChunk(district, 2000, async (r) => {
return await tx.$kysely
.insertInto("District")
.columns([
"id",
"name",
"nameEN",
"provinceId",
"createdBy",
"createdAt",
"updatedBy",
"updatedAt",
])
.values(r.map((v) => ({ ...v, ...meta })))
.onConflict((oc) =>
oc.column("id").doUpdateSet({
name: (eb) => eb.ref("excluded.name"),
nameEN: (eb) => eb.ref("excluded.nameEN"),
provinceId: (eb) => eb.ref("excluded.provinceId"),
updatedAt: (eb) => eb.ref("excluded.updatedAt"),
}),
)
.execute();
}),
);
await Promise.all(
splitChunk(subDistrict, 1000, async (r) => {
return await tx.$kysely
.insertInto("SubDistrict")
.columns([
"id",
"name",
"nameEN",
"districtId",
"createdBy",
"createdAt",
"updatedBy",
"updatedAt",
])
.values(r.map((v) => ({ ...v, ...meta })))
.onConflict((oc) =>
oc.column("id").doUpdateSet({
name: (eb) => eb.ref("excluded.name"),
nameEN: (eb) => eb.ref("excluded.nameEN"),
districtId: (eb) => eb.ref("excluded.districtId"),
updatedAt: (eb) => eb.ref("excluded.updatedAt"),
}),
)
.execute();
}),
);
});
console.log("[INFO]: Sync thailand province, district and subdistrict, OK.");
}
export async function initEmploymentOffice() {
const name = (provinceName: string) => `สำนักงานจัดหางานจังหวัด${provinceName}`;
const nameEN = (provinceNameEN: string) => `${provinceNameEN} Employment Office`;
const nameSpecial = (provinceName: string, areaNo: number) =>
`สำนักงานจัดหางาน${provinceName} พื้นที่ ${areaNo}`;
const nameSpecialEN = (provinceNameEN: string, areaNo: number) =>
`${provinceNameEN} Employment Office Area ${areaNo}`;
const special: Record<string, { [key: string]: string[] }> = {
"10": {
"1": ["1004", "1007", "1012", "1028", "1031"],
"2": ["1021", "1024", "1035", "1049", "1050"],
"3": ["1009", "1032", "1033", "1034", "1039", "1047"],
"4": ["1006", "1038", "1043", "1027", "1045"],
"5": ["1003", "1010", "1011", "1042", "1044", "1046"],
"6": ["1015", "1016", "1018", "1020", "1025"],
"7": ["1019", "1022", "1023", "1040", "1048"],
"8": ["1001", "1002", "1008", "1013"],
"9": ["1005", "1029", "1030", "1041"],
"10": ["1014", "1017", "1026", "1036", "1037"],
},
};
const list = await prisma.province.findMany();
await prisma.$transaction(async (tx) => {
await Promise.all(
list
.map(async (province) => {
if (special[province.id]) {
await tx.employmentOffice.deleteMany({
where: { provinceId: province.id, district: { none: {} } },
});
return await Promise.all(
Object.entries(special[province.id]).map(async ([key, val]) => {
const id = province.id + "-" + key.padStart(2, "0");
return tx.employmentOffice.upsert({
where: { id },
create: {
id,
name: nameSpecial(province.name, +key),
nameEN: nameSpecialEN(province.nameEN, +key),
provinceId: province.id,
district: {
createMany: {
data: val.map((districtId) => ({ districtId })),
skipDuplicates: true,
},
},
},
update: {
id,
name: nameSpecial(province.name, +key),
nameEN: nameSpecialEN(province.nameEN, +key),
provinceId: province.id,
district: {
deleteMany: { districtId: { notIn: val } },
createMany: {
data: val.map((districtId) => ({ districtId })),
skipDuplicates: true,
},
},
},
});
}),
);
}
return tx.employmentOffice.upsert({
where: { id: province.id },
create: {
id: province.id,
name: name(province.name),
nameEN: nameEN(province.nameEN),
provinceId: province.id,
},
update: {
name: name(province.name),
nameEN: nameEN(province.nameEN),
provinceId: province.id,
},
});
})
.flat(),
);
});
console.log("[INFO]: Sync employment office, OK.");
}