Skip to content

Commit

Permalink
feat: improve seeder (#466)
Browse files Browse the repository at this point in the history
  • Loading branch information
fityannugroho authored Nov 23, 2024
1 parent 1ed40d5 commit dcf7ef4
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 243 deletions.
8 changes: 8 additions & 0 deletions prisma/mongodb/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ model Regency {
@@map("regencies")
}

model SeederLogs {
id String @id @default(auto()) @map("_id") @db.ObjectId
dataVersion String @map("data_version")
createdAt DateTime @default(now()) @map("created_at")
@@map("seeder_logs")
}

model Village {
id String @id @default(auto()) @map("_id") @db.ObjectId
code String @unique
Expand Down
116 changes: 12 additions & 104 deletions prisma/mongodb/seeder.ts
Original file line number Diff line number Diff line change
@@ -1,123 +1,31 @@
import { areArraysEqual } from '@/common/utils/array';
import {
getDistricts,
getIslands,
getProvinces,
getRegencies,
getVillages,
} from '@/common/utils/data';
import { PrismaClient } from '@prisma/client';
import { Areas } from 'idn-area-data';
import { Seeder } from '../seeder';
import { Area, Seeder } from '../seeder';

export class MongodbSeeder extends Seeder {
constructor(prisma: PrismaClient) {
super(prisma);
}

async hasProvinceChanges(): Promise<boolean> {
const [newProvinces, oldProvinces] = await Promise.all([
getProvinces(),
this.prisma.province.findMany(),
]);
async deleteAreas(area: Area): Promise<number> {
const mongoCollectionMap = {
province: 'provinces',
regency: 'regencies',
district: 'districts',
village: 'villages',
island: 'islands',
};

return !areArraysEqual(newProvinces, oldProvinces, ['code', 'name']);
}

async hasRegencyChanges(): Promise<boolean> {
const [newRegencies, oldRegencies] = await Promise.all([
getRegencies(),
this.prisma.regency.findMany(),
]);

return !areArraysEqual(newRegencies, oldRegencies, [
'code',
'name',
'provinceCode',
]);
}

async hasDistrictChanges(): Promise<boolean> {
const [newDistricts, oldDistricts] = await Promise.all([
getDistricts(),
this.prisma.district.findMany(),
]);

return !areArraysEqual(newDistricts, oldDistricts, [
'code',
'name',
'regencyCode',
]);
}

async hasIslandChanges(): Promise<boolean> {
const [newIslands, oldIslands] = await Promise.all([
getIslands(),
this.prisma.island.findMany(),
]);

return !areArraysEqual(newIslands, oldIslands, [
'code',
'name',
'regencyCode',
'isPopulated',
'isOutermostSmall',
]);
}

async hasVillageChanges(): Promise<boolean> {
const [newVillages, oldVillages] = await Promise.all([
getVillages(),
this.prisma.village.findMany(),
]);

return !areArraysEqual(newVillages, oldVillages, [
'code',
'name',
'districtCode',
]);
}

/**
* Delete all data in a collection.
*/
protected async deleteCollection(collection: Areas) {
// Skip TypeScript checking because `$runCommandRaw()` method only available for mongodb provider.
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return await this.prisma.$runCommandRaw({
delete: collection,
// @ts-ignore Skip TypeScript checking because `$runCommandRaw()` method only available for mongodb provider.
const res = await this.prisma.$runCommandRaw({
delete: mongoCollectionMap[area],
deletes: [
{
q: {},
limit: 0,
},
],
});
}

async deleteProvinces(): Promise<number> {
const res = await this.deleteCollection('provinces');
return res.n as number;
}

async deleteRegencies(): Promise<number> {
const res = await this.deleteCollection('regencies');
return res.n as number;
}

async deleteDistricts(): Promise<number> {
const res = await this.deleteCollection('districts');
return res.n as number;
}

async deleteVillages(): Promise<number> {
const res = await this.deleteCollection('villages');
return res.n as number;
}

async deleteIslands(): Promise<number> {
const res = await this.deleteCollection('islands');
return res.n as number;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- CreateTable
CREATE TABLE `seeder_logs` (
`id` INTEGER NOT NULL AUTO_INCREMENT,
`data_version` VARCHAR(255) NOT NULL,
`created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),

PRIMARY KEY (`id`)
) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
8 changes: 8 additions & 0 deletions prisma/mysql/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ model Regency {
@@map("regencies")
}

model SeederLogs {
id Int @id @default(autoincrement())
dataVersion String @map("data_version") @db.VarChar(255)
createdAt DateTime @default(now()) @map("created_at")
@@map("seeder_logs")
}

model Village {
code String @id @db.VarChar(10)
districtCode String @map("district_code") @db.VarChar(6)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- CreateTable
CREATE TABLE "seeder_logs" (
"id" SERIAL NOT NULL,
"data_version" VARCHAR(255) NOT NULL,
"created_at" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "seeder_logs_pkey" PRIMARY KEY ("id")
);
8 changes: 8 additions & 0 deletions prisma/postgresql/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ model Regency {
@@map("regencies")
}

model SeederLogs {
id Int @id @default(autoincrement())
dataVersion String @map("data_version") @db.VarChar(255)
createdAt DateTime @default(now()) @map("created_at")
@@map("seeder_logs")
}

model Village {
code String @id @db.VarChar(10)
districtCode String @map("district_code") @db.VarChar(6)
Expand Down
29 changes: 13 additions & 16 deletions prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,32 +17,29 @@ async function main() {
seeder = new MongodbSeeder(prisma);
}

const hasDataChanges = timify(
seeder.hasDataChanges.bind(seeder),
'check-data-changes',
);

// Skip the seeder if if there are no data changes.
console.log('Checking for data changes...\n');
if (!(await hasDataChanges())) {
if (!(await seeder.hasDataChanges())) {
console.log('There are no data changes. Seeder is skipped.');
return;
}
console.log('Data changes found!');

console.log('Deleting all data...');
await timify(seeder.deleteVillages.bind(seeder), 'delete-villages')();
await timify(seeder.deleteIslands.bind(seeder), 'delete-islands')();
await timify(seeder.deleteDistricts.bind(seeder), 'delete-districts')();
await timify(seeder.deleteRegencies.bind(seeder), 'delete-regencies')();
await timify(seeder.deleteProvinces.bind(seeder), 'delete-provinces')();
await timify(() => seeder.deleteAreas('village'), 'delete-villages')();
await timify(() => seeder.deleteAreas('district'), 'delete-districts')();
await timify(() => seeder.deleteAreas('island'), 'delete-islands')();
await timify(() => seeder.deleteAreas('regency'), 'delete-regencies')();
await timify(() => seeder.deleteAreas('province'), 'delete-provinces')();

console.log('Inserting all data...');
await timify(seeder.insertProvinces.bind(seeder), 'insert-provinces')();
await timify(seeder.insertRegencies.bind(seeder), 'insert-regencies')();
await timify(seeder.insertDistricts.bind(seeder), 'insert-districts')();
await timify(seeder.insertIslands.bind(seeder), 'insert-islands')();
await timify(seeder.insertVillages.bind(seeder), 'insert-villages')();
await timify(() => seeder.insertAreas('province'), 'insert-provinces')();
await timify(() => seeder.insertAreas('regency'), 'insert-regencies')();
await timify(() => seeder.insertAreas('island'), 'insert-islands')();
await timify(() => seeder.insertAreas('district'), 'insert-districts')();
await timify(() => seeder.insertAreas('village'), 'insert-villages')();

await seeder.generateLog();
}

main()
Expand Down
Loading

0 comments on commit dcf7ef4

Please sign in to comment.