Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create database seeding script #137

Merged
merged 14 commits into from
Jul 16, 2024
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"author": "",
"license": "ISC",
"dependencies": {
"@faker-js/faker": "^8.4.1",
"@tsed/passport": "^7.57.1",
"bcrypt": "^5.1.0",
"body-parser": "^1.20.2",
Expand Down
26 changes: 14 additions & 12 deletions src/app.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
import express from 'express'
import type { Express } from 'express'
import bodyParser from 'body-parser'
import cookieParser from 'cookie-parser'
import cors from 'cors'
import { dataSource } from './configs/dbConfig'
import authRouter from './routes/auth/auth.route'
import profileRouter from './routes/profile/profile.route'
import adminRouter from './routes/admin/admin.route'
import mentorRouter from './routes/mentor/mentor.route'
import categoryRouter from './routes/category/category.route'
import type { Express } from 'express'
import express from 'express'
import fs from 'fs'
import passport from 'passport'
import { dataSource } from './configs/dbConfig'
import { CLIENT_URL } from './configs/envConfig'
import './configs/google-passport'
import './configs/linkedin-passport'
import { CLIENT_URL } from './configs/envConfig'
import cookieParser from 'cookie-parser'
import menteeRouter from './routes/mentee/mentee.route'
import fs from 'fs'
import adminRouter from './routes/admin/admin.route'
import authRouter from './routes/auth/auth.route'
import categoryRouter from './routes/category/category.route'
import emailRouter from './routes/emails/emails.route'
import menteeRouter from './routes/mentee/mentee.route'
import mentorRouter from './routes/mentor/mentor.route'
import profileRouter from './routes/profile/profile.route'
import seedRouter from './routes/seeds/seeds.route'

const app = express()
const staticFolder = 'uploads'
Expand Down Expand Up @@ -43,6 +44,7 @@ app.use('/api/mentors', mentorRouter)
app.use('/api/mentees', menteeRouter)
app.use('/api/categories', categoryRouter)
app.use('/api/emails', emailRouter)
app.use('/api/seeds', seedRouter)

if (!fs.existsSync(staticFolder)) {
fs.mkdirSync(staticFolder, { recursive: true })
Expand Down
22 changes: 22 additions & 0 deletions src/controllers/seed.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import type { Request, Response } from 'express'
import { seedDatabaseService } from '../services/seed.service'

export const seedDbController = async (
req: Request,
res: Response
): Promise<{ statusCode: number; message?: string }> => {
try {
const { statusCode, message } = await seedDatabaseService()

return res.status(statusCode).json({ message })
} catch (err) {
if (err instanceof Error) {
console.error('Error executing query', err)
return res
.status(500)
.json({ error: 'Internal server error', message: err.message })
}

throw err
}
}
8 changes: 8 additions & 0 deletions src/routes/seeds/seeds.route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import express from 'express'
import { seedDbController } from '../../controllers/seed.controller'

const seedRouter = express.Router()

seedRouter.get('/seed', seedDbController)
dsmabulage marked this conversation as resolved.
Show resolved Hide resolved

export default seedRouter
185 changes: 185 additions & 0 deletions src/services/seed.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
import { faker } from '@faker-js/faker'
import { dataSource } from '../configs/dbConfig'
import Category from '../entities/category.entity'
import Email from '../entities/email.entity'
import EmailTemplate from '../entities/emailTemplate.entity'
import Mentee from '../entities/mentee.entity'
import Mentor from '../entities/mentor.entity'
import Platform from '../entities/platform.entity'
import Profile from '../entities/profile.entity'
import { ApplicationStatus, EmailStatusTypes, ProfileTypes } from '../enums'

export const seedDatabaseService = async (): Promise<{
statusCode: number
message: string
}> => {
const queryRunner = dataSource.createQueryRunner()
await queryRunner.connect()
await queryRunner.startTransaction()

try {
const profileRepository = queryRunner.manager.getRepository(Profile)
const categoryRepository = queryRunner.manager.getRepository(Category)
const emailRepository = queryRunner.manager.getRepository(Email)
const emailTemplateRepository =
queryRunner.manager.getRepository(EmailTemplate)
const menteeRepository = queryRunner.manager.getRepository(Mentee)
const mentorRepository = queryRunner.manager.getRepository(Mentor)
const platformRepository = queryRunner.manager.getRepository(Platform)

// Find and remove existing data
await menteeRepository.remove(await menteeRepository.find())
await mentorRepository.remove(await mentorRepository.find())
await profileRepository.remove(await profileRepository.find())
await platformRepository.remove(await platformRepository.find())
await categoryRepository.remove(await categoryRepository.find())
await emailRepository.remove(await emailRepository.find())
await emailTemplateRepository.remove(await emailTemplateRepository.find())

const genProfiles = faker.helpers.multiple(createRandomProfile, {
count: 100
})

const profiles = await profileRepository.save(genProfiles)

const genEmails = faker.helpers.multiple(
() => {
return {
recipient: faker.internet.email(),
subject: faker.lorem.sentence(),
content: faker.lorem.paragraph(),
state: faker.helpers.enumValue(EmailStatusTypes)
}
},
{
count: 100
}
)

await emailRepository.save(genEmails)

const genEmailTemplates = faker.helpers.multiple(
() => {
return {
subject: faker.lorem.sentence(),
content: faker.lorem.paragraph()
}
},
{
count: 100
}
)

await emailTemplateRepository.save(genEmailTemplates)

const genCategories = faker.helpers.multiple(
() => {
return {
category: faker.lorem.word()
}
},
{
count: 100
}
)
const categories = await categoryRepository.save(genCategories)

const genPlatforms = faker.helpers.multiple(
() => {
return {
description: faker.lorem.sentence(),
mentor_questions: {
name: faker.lorem.word(),
email: faker.internet.email()
} as unknown as JSON,
image_url: faker.image.url(),
landing_page_url: faker.internet.url(),
title: faker.lorem.word()
}
},
{
count: 100
}
)

await platformRepository.save(genPlatforms)

const genMentors = (
categories: Category[],
profiles: Profile[]
): Mentor[] => {
const firstTenProfiles = profiles.slice(0, 10)

return firstTenProfiles.map((profile, index) => {
const category = categories[index]
return createMentor(category, profile)
})
}
const mentorsEntities = genMentors(categories, profiles)
const mentors = await mentorRepository.save(mentorsEntities)

const genMentees = (mentors: Mentor[], profiles: Profile[]): Mentee[] => {
const lastProfilesWithoutFirstTen = profiles.slice(10, profiles.length)

return lastProfilesWithoutFirstTen.map((profile, index) => {
const mentor =
mentors[faker.number.int({ min: 0, max: mentors.length - 1 })]
return new Mentee(
faker.helpers.enumValue(ApplicationStatus),
{
name: faker.lorem.word(),
email: faker.internet.email()
},
profile,
mentor
)
})
}

const menteesEntities = genMentees(mentors, profiles)

await menteeRepository.save(menteesEntities)

await queryRunner.commitTransaction()

return {
statusCode: 200,
message: 'Successfully seeded the database'
}
} catch (err) {
console.log(err)
await queryRunner.rollbackTransaction()
return {
statusCode: 500,
message: 'Internal server error'
}
} finally {
await queryRunner.release()
}
}

const createRandomProfile = (): Partial<Profile> => {
const profile = {
primary_email: faker.internet.email(),
first_name: faker.person.firstName(),
last_name: faker.person.lastName(),
image_url: faker.image.avatar(),
type: faker.helpers.enumValue(ProfileTypes),
password: '12345'
}

return profile
}

const createMentor = (category: Category, profile: Profile): Mentor => {
return {
state: faker.helpers.enumValue(ApplicationStatus),
category: category,

Check warning on line 177 in src/services/seed.service.ts

View workflow job for this annotation

GitHub Actions / build

Expected property shorthand
application: {
name: faker.lorem.word(),
email: faker.internet.email()
},
availability: faker.datatype.boolean(),
profile: profile

Check warning on line 183 in src/services/seed.service.ts

View workflow job for this annotation

GitHub Actions / build

Expected property shorthand
} as unknown as Mentor
}
Loading