diff --git a/package.json b/package.json index b79cdac..bc44184 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,10 @@ "db:migrate": "drizzle-kit migrate", "db:push": "drizzle-kit push", "db:studio": "drizzle-kit studio", - "db:seed": "dotenv npx tsx ./src/server/db/seed.ts", + "db:seed:educations": "dotenv npx tsx ./src/server/db/seed/educations.seed.ts", + "db:seed:license": "dotenv npx tsx ./src/server/db/seed/license.seed.ts", + "db:seed:users": "dotenv npx tsx ./src/server/db/seed/user.seed.ts", + "db:seed:all": "dotenv npx tsx ./src/server/db/seed/index.ts", "db:schema:generate": "node --experimental-specifier-resolution=node --loader ts-node/esm src/server/db/dbml-generator/dbml.ts && dbml-renderer -i schema.dbml -o erd.svg", "dev": "next dev", "lint": "next lint", diff --git a/src/server/db/seed.ts b/src/server/db/seed.ts deleted file mode 100644 index 705de24..0000000 --- a/src/server/db/seed.ts +++ /dev/null @@ -1,157 +0,0 @@ -import { hash } from "bcrypt"; -import { env } from "~/env"; -import { db } from "../db/index"; -import { eq } from "drizzle-orm"; -import { - addresses, - AddressType, - cities, - countries, - languages, - users, -} from "../db/schema"; -import { populateEducations } from "./seed/education.seed"; -import { populateLicenses } from "./seed/license.seed"; -import { generateUsers, SALT_OR_ROUNDS, generateAdmin } from "./seed/user.seed"; - -const generateCountriesWithCities = async (): Promise => { - const _cities = [ - { name: "Rijeka", zip: "51000" }, - { name: "Zagreb", zip: "10000" }, - { name: "Split", zip: "21000" }, - { name: "Osijek", zip: "31000" }, - { name: "Dubrovnik", zip: "20000" }, - { name: "Ljubljana", zip: "1000" }, - ]; - const _countries = ["Croatia", "Slovenia"]; - - const existingCities = await db.query.cities.findMany({ - columns: { id: true }, - }); - if (existingCities.length) return existingCities.map(({ id }) => id); - - const existingCountries = await db.query.countries.findMany(); - let insertedCountries: { name: string; insertedId: string }[]; - if (!existingCountries.length) { - insertedCountries = await db - .insert(countries) - .values( - _countries.map((_country) => ({ - name: _country, - })), - ) - .returning({ insertedId: countries.id, name: countries.name }); - } else { - insertedCountries = existingCountries.map((country) => ({ - name: country.name, - insertedId: country.id, - })); - } - - const insertedCities = await db - .insert(cities) - .values( - _cities.map((_city) => ({ - name: _city.name, - postalCode: _city.zip, - countryId: - _city.name === "Ljubljana" - ? insertedCountries.find((c) => c.name === "Slovenia")?.insertedId - : insertedCountries.find((c) => c.name === "Croatia")?.insertedId, - })), - ) - .returning({ insertedId: cities.id }); - - return insertedCities.map(({ insertedId }) => insertedId); -}; - -const generateAddresses = async (cityIds: string[]): Promise => { - const existingAddresses = await db.query.addresses.findMany({ - columns: { id: true }, - }); - if (existingAddresses.length) return existingAddresses.map(({ id }) => id); - - const streetNames = ["Foo", "Bar", "Baz", "Qux", "Quux", "Corge"]; - - const _addresses: { street: string; streetNumber: string }[] = streetNames - .concat(streetNames) - .concat(streetNames) - .concat(streetNames) - .map((street, index) => ({ street, streetNumber: (index + 1).toString() })); - - const insertedAddresses = await db - .insert(addresses) - .values( - _addresses.map((_address, i) => ({ - street: _address.street, - streetNumber: _address.streetNumber, - cityId: cityIds[i % cityIds.length], - type: AddressType.PERMANENT_RESIDENCE, - })), - ) - .returning({ insertedId: addresses.id }); - - return insertedAddresses.map((address) => address.insertedId); -}; - -const generateLanguages = async (): Promise => { - const _languages = [ - "Croatian", - "English", - "German", - "Italian", - "Spanish", - "French", - "Russian", - ]; - - const existingLanguages = await db.query.languages.findMany({ - columns: { id: true }, - }); - if (existingLanguages.length) return existingLanguages.map(({ id }) => id); - const items: { name: string }[] = []; - for (const lang of _languages) { - items.push({ name: lang }); - } - - const res = await db.insert(languages).values(items).returning(); - return res.map(({ id }) => id); -}; - -const main = async () => { - const adminPassword = await hash(env.ADMIN_PASSWORD, SALT_OR_ROUNDS); - const email = "admin@dck-pgz.hr"; - - let _licences = await db.query.licenses.findMany(); - if (!_licences.length) { - _licences = await populateLicenses(); - } - - let _educations = await db.query.educations.findMany(); - if (!_educations.length) { - _educations = await populateEducations(); - } - - const cityIds = await generateCountriesWithCities(); - const addressIds = await generateAddresses(cityIds); - const languageIds = await generateLanguages(); - - const adminExists = await db.query.users.findFirst({ - where: eq(users.email, email), - }); - if (!adminExists) { - await generateAdmin( - email, - adminPassword, - _licences, - languageIds, - addressIds, - ); - } - - await generateUsers(addressIds, languageIds, _licences); -}; - -main() - .then(() => (console.log("Seed completed"), process.exit(0))) - .catch(console.error); diff --git a/src/server/db/seed/education.seed.ts b/src/server/db/seed/education.seed.ts index 5add162..9de0499 100644 --- a/src/server/db/seed/education.seed.ts +++ b/src/server/db/seed/education.seed.ts @@ -14,6 +14,7 @@ interface Education { topics?: string; type: EducationType; } + const headerMapping: Record = { Title: "title", Description: "description", @@ -24,11 +25,13 @@ const headerMapping: Record = { "Trajanje obnove": "renewal_duration", Teme: "topics", }; + const sheetNameMapping: Record = { "za-volontere": EducationType.VOLUNTEERS, "za-javnost": EducationType.PUBLIC, "za-djelatnike": EducationType.EMPLOYEE, }; + const readExcelFile = (filePath: string): Education[] => { const fileBuffer = readFileSync(filePath); const workbook = XLSX.read(fileBuffer, { type: "buffer" }); @@ -63,9 +66,23 @@ const readExcelFile = (filePath: string): Education[] => { return educations; }; + export const populateEducations = async () => { const filePath = "scripts/educations_parser/edukacije.xlsx"; const _educations = readExcelFile(filePath); return db.insert(educations).values(_educations).returning(); }; + +export const getEducations = async () => { + let _educations = await db.query.educations.findMany(); + if (!_educations.length) { + _educations = await populateEducations(); + } +}; +getEducations() + .then((educations) => educations) + .catch((err) => { + console.log(err); + process.exit(1); + }); diff --git a/src/server/db/seed/index.ts b/src/server/db/seed/index.ts new file mode 100644 index 0000000..1dc117b --- /dev/null +++ b/src/server/db/seed/index.ts @@ -0,0 +1,10 @@ +import { getEducations } from "./education.seed"; +import { getLicenses } from "./license.seed"; +import { getAdmins, getUsers } from "./user.seed"; + +void (async () => { + await getLicenses(); + await getUsers(); + await getAdmins(); + await getEducations(); +})(); diff --git a/src/server/db/seed/license.seed.ts b/src/server/db/seed/license.seed.ts index 9821932..ad734e3 100644 --- a/src/server/db/seed/license.seed.ts +++ b/src/server/db/seed/license.seed.ts @@ -10,3 +10,18 @@ export const populateLicenses = async () => { return db.insert(licenses).values(_licenses).returning(); }; + +export const getLicenses = async () => { + let _licences = await db.query.licenses.findMany(); + if (!_licences.length) { + _licences = await populateLicenses(); + } + return _licences; +}; + +getLicenses() + .then((licenses) => licenses) + .catch((err) => { + console.log(err); + process.exit(1); + }); diff --git a/src/server/db/seed/user.seed.ts b/src/server/db/seed/user.seed.ts index b36c271..a19a635 100644 --- a/src/server/db/seed/user.seed.ts +++ b/src/server/db/seed/user.seed.ts @@ -1,12 +1,18 @@ +import { env } from "~/env"; import { type PgTransaction } from "drizzle-orm/pg-core"; import { eq } from "drizzle-orm"; import { hash } from "bcrypt"; import { db } from ".."; import { + addresses, + AddressType, + cities, ClothingSize, + countries, EducationLevel, LanguageLevel, + languages, profiles, profilesAddresses, profileSkills, @@ -17,8 +23,13 @@ import { users, workStatuses, } from "../schema"; +import { getLicenses } from "./license.seed"; + +export const SALT_OR_ROUNDS = 10; + const names = ["John", "Jane", "Alice", "Bob", "Charlie", "Diana"]; const surnames = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia"]; + export const getRandomLanguages = ( userId: string, languageIds: string[], @@ -37,6 +48,7 @@ export const getRandomLanguages = ( level: randomLevel, })); }; + export const insertWorkStatus = async ( // eslint-disable-next-line @typescript-eslint/no-explicit-any tx: PgTransaction, @@ -71,6 +83,7 @@ export const insertWorkStatus = async ( .values(_workStatuses[Math.floor(Math.random() * _workStatuses.length)]!) .returning(); }; + export const generateProfileSkills = ( profileId: string, ): { name: string; description: string; profileId: string }[] => { @@ -90,6 +103,7 @@ export const generateProfileSkills = ( } return items; }; + const getRandomLoremIpsum = (length: number): string => { const loremIpsum = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."; @@ -107,7 +121,7 @@ const getRandomLoremIpsum = (length: number): string => { // Truncate to the exact desired length if necessary return result.substring(0, length); }; -export const SALT_OR_ROUNDS = 10; + export const generateUsers = async ( addressIds: string[], languageIds: string[], @@ -205,6 +219,7 @@ export const generateUsers = async ( }); } } + return await db.query.users.findMany(); }; export async function generateAdmin( @@ -273,4 +288,162 @@ export async function generateAdmin( ); } }); + return await db.query.users.findMany({ + where: eq(users.email, email), + }); } +const generateCountriesWithCities = async (): Promise => { + const _cities = [ + { name: "Rijeka", zip: "51000" }, + { name: "Zagreb", zip: "10000" }, + { name: "Split", zip: "21000" }, + { name: "Osijek", zip: "31000" }, + { name: "Dubrovnik", zip: "20000" }, + { name: "Ljubljana", zip: "1000" }, + ]; + const _countries = ["Croatia", "Slovenia"]; + + const existingCities = await db.query.cities.findMany({ + columns: { id: true }, + }); + if (existingCities.length) return existingCities.map(({ id }) => id); + + const existingCountries = await db.query.countries.findMany(); + let insertedCountries: { name: string; insertedId: string }[]; + if (!existingCountries.length) { + insertedCountries = await db + .insert(countries) + .values( + _countries.map((_country) => ({ + name: _country, + })), + ) + .returning({ insertedId: countries.id, name: countries.name }); + } else { + insertedCountries = existingCountries.map((country) => ({ + name: country.name, + insertedId: country.id, + })); + } + + const insertedCities = await db + .insert(cities) + .values( + _cities.map((_city) => ({ + name: _city.name, + postalCode: _city.zip, + countryId: + _city.name === "Ljubljana" + ? insertedCountries.find((c) => c.name === "Slovenia")?.insertedId + : insertedCountries.find((c) => c.name === "Croatia")?.insertedId, + })), + ) + .returning({ insertedId: cities.id }); + + return insertedCities.map(({ insertedId }) => insertedId); +}; + +const generateAddresses = async (cityIds: string[]): Promise => { + const existingAddresses = await db.query.addresses.findMany({ + columns: { id: true }, + }); + if (existingAddresses.length) return existingAddresses.map(({ id }) => id); + + const streetNames = ["Foo", "Bar", "Baz", "Qux", "Quux", "Corge"]; + + const _addresses: { street: string; streetNumber: string }[] = streetNames + .concat(streetNames) + .concat(streetNames) + .concat(streetNames) + .map((street, index) => ({ street, streetNumber: (index + 1).toString() })); + + const insertedAddresses = await db + .insert(addresses) + .values( + _addresses.map((_address, i) => ({ + street: _address.street, + streetNumber: _address.streetNumber, + cityId: cityIds[i % cityIds.length], + type: AddressType.PERMANENT_RESIDENCE, + })), + ) + .returning({ insertedId: addresses.id }); + + return insertedAddresses.map((address) => address.insertedId); +}; + +const generateLanguages = async (): Promise => { + const _languages = [ + "Croatian", + "English", + "German", + "Italian", + "Spanish", + "French", + "Russian", + ]; + + const existingLanguages = await db.query.languages.findMany({ + columns: { id: true }, + }); + if (existingLanguages.length) return existingLanguages.map(({ id }) => id); + const items: { name: string }[] = []; + for (const lang of _languages) { + items.push({ name: lang }); + } + + const res = await db.insert(languages).values(items).returning(); + return res.map(({ id }) => id); +}; + +export const getUsers = async () => { + const cityIds = await generateCountriesWithCities(); + const addressIds = await generateAddresses(cityIds); + const languageIds = await generateLanguages(); + const _licences = await getLicenses(); + let _users = await db.query.users.findMany(); + if (!_users.length) { + _users = await generateUsers(addressIds, languageIds, _licences); + } + + return _users; +}; +const email = "admin@dck-pgz.hr"; +const adminPassword = await hash(env.ADMIN_PASSWORD, SALT_OR_ROUNDS); + +export const getAdmins = async () => { + const adminExists = await db.query.users.findFirst({ + where: eq(users.email, email), + }); + let _admins = await db.query.users.findMany({ + where: eq(users.email, email), + }); + if (!adminExists) { + const _licences = await getLicenses(); + const cityIds = await generateCountriesWithCities(); + const addressIds = await generateAddresses(cityIds); + const languageIds = await generateLanguages(); + _admins = await generateAdmin( + email, + adminPassword, + _licences, + languageIds, + addressIds, + ); + } + return _admins; +}; + +getUsers() + .then((users) => users) + .catch((err) => { + console.log(err); + process.exit(1); + }); + +getAdmins() + .then((admins) => admins) + .catch((err) => { + console.log(err); + process.exit(1); + });