seed
This commit is contained in:
Generated
+33
@@ -43,6 +43,7 @@
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@mikro-orm/cli": "^6.5.8",
|
||||
"@mikro-orm/seeder": "^6.5.8",
|
||||
"@nestjs/cli": "^11.0.0",
|
||||
"@nestjs/schematics": "^11.0.0",
|
||||
"@nestjs/testing": "^11.0.1",
|
||||
@@ -3529,6 +3530,38 @@
|
||||
"@mikro-orm/core": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/seeder": {
|
||||
"version": "6.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@mikro-orm/seeder/-/seeder-6.5.8.tgz",
|
||||
"integrity": "sha512-EVfXNJ+Q7I1jKLlYwWDdQ/67DxhuBSfS2U/XKKo/+uEaxGBl5vDe8kV3RNRwx8I9x6DHsQpt1NzJL+JS3fSt3w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fs-extra": "11.3.2",
|
||||
"globby": "11.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 18.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@mikro-orm/core": "^6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@mikro-orm/seeder/node_modules/fs-extra": {
|
||||
"version": "11.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.2.tgz",
|
||||
"integrity": "sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.14"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "0.2.12",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"db:create": "npx mikro-orm schema:create --run --config ./src/config/mikro-orm.config.dev.ts",
|
||||
"db:update": "npx mikro-orm schema:update --run --config ./src/config/mikro-orm.config.dev.ts",
|
||||
"db:drop": "npx mikro-orm schema:drop --run --config ./src/config/mikro-orm.config.dev.ts",
|
||||
"db:seed": "npx mikro-orm seeder:run --config ./src/config/mikro-orm.config.dev.ts",
|
||||
"build": "nest build",
|
||||
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
|
||||
"start": "nest start dist/main",
|
||||
@@ -54,6 +55,7 @@
|
||||
"ulid": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mikro-orm/seeder": "^6.5.8",
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.18.0",
|
||||
"@mikro-orm/cli": "^6.5.8",
|
||||
|
||||
@@ -62,6 +62,11 @@ export default defineConfig({
|
||||
},
|
||||
connect: true,
|
||||
allowGlobalContext: true,
|
||||
seeder: {
|
||||
path: './dist/seeders',
|
||||
pathTs: './src/seeders',
|
||||
defaultSeeder: 'DatabaseSeeder',
|
||||
},
|
||||
driverOptions: {
|
||||
connection: {
|
||||
keepAlive: true,
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { Collection, Entity, ManyToMany, OneToOne, Property } from '@mikro-orm/core';
|
||||
import { Collection, Entity, ManyToMany, ManyToOne, Property } from '@mikro-orm/core';
|
||||
import { Category } from './category.entity';
|
||||
import { BaseEntity } from '../../../common/entities/base.entity';
|
||||
import { Restaurant } from '../../../modules/restaurants/entities/restaurant.entity';
|
||||
|
||||
@Entity({ tableName: 'foods' })
|
||||
export class Food extends BaseEntity {
|
||||
@OneToOne(() => Restaurant)
|
||||
@ManyToOne(() => Restaurant)
|
||||
restaurant: Restaurant;
|
||||
|
||||
@ManyToMany(() => Category)
|
||||
|
||||
@@ -0,0 +1,466 @@
|
||||
import type { EntityManager } from '@mikro-orm/core';
|
||||
import { Seeder } from '@mikro-orm/seeder';
|
||||
import { Category } from '../modules/foods/entities/category.entity';
|
||||
import { Food } from '../modules/foods/entities/food.entity';
|
||||
import { Admin } from '../modules/admin/entities/admin.entity';
|
||||
import { Permission } from '../modules/admin/entities/permission.entity';
|
||||
import { Role } from '../modules/admin/entities/role.entity';
|
||||
import { Restaurant } from '../modules/restaurants/entities/restaurant.entity';
|
||||
import { User } from '../modules/users/entities/user.entity';
|
||||
|
||||
export class DatabaseSeeder extends Seeder {
|
||||
async run(em: EntityManager) {
|
||||
// 1. Create Permissions (English)
|
||||
const permissions = [
|
||||
{ name: 'manage_restaurants' },
|
||||
{ name: 'manage_foods' },
|
||||
{ name: 'manage_categories' },
|
||||
{ name: 'manage_orders' },
|
||||
{ name: 'manage_admins' },
|
||||
{ name: 'manage_users' },
|
||||
{ name: 'view_reports' },
|
||||
{ name: 'manage_finances' },
|
||||
];
|
||||
|
||||
const createdPermissions: Permission[] = [];
|
||||
for (const permData of permissions) {
|
||||
let permission = await em.findOne(Permission, { name: permData.name });
|
||||
if (!permission) {
|
||||
permission = em.create(Permission, permData);
|
||||
em.persist(permission);
|
||||
}
|
||||
createdPermissions.push(permission);
|
||||
}
|
||||
|
||||
// 2. Create Roles (English)
|
||||
const ownerRole = await em.findOne(Role, { name: 'owner' });
|
||||
if (!ownerRole) {
|
||||
const role = em.create(Role, { name: 'owner' });
|
||||
// Add all permissions to owner
|
||||
createdPermissions.forEach(p => role.permissions.add(p));
|
||||
em.persist(role);
|
||||
}
|
||||
|
||||
const accountantRole = await em.findOne(Role, { name: 'accountant' });
|
||||
if (!accountantRole) {
|
||||
const role = em.create(Role, { name: 'accountant' });
|
||||
// Add financial permissions to accountant
|
||||
const financialPerms = createdPermissions.filter(
|
||||
p => p.name === 'view_reports' || p.name === 'manage_finances' || p.name === 'manage_orders',
|
||||
);
|
||||
financialPerms.forEach(p => role.permissions.add(p));
|
||||
em.persist(role);
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
|
||||
// Get roles after flush
|
||||
const owner = await em.findOne(Role, { name: 'owner' });
|
||||
const accountant = await em.findOne(Role, { name: 'accountant' });
|
||||
|
||||
// 3. Create Restaurants (Farsi)
|
||||
const zhivanRestaurant = await em.findOne(Restaurant, { slug: 'zhivan' });
|
||||
if (!zhivanRestaurant) {
|
||||
const restaurant = em.create(Restaurant, {
|
||||
name: 'ژیوان',
|
||||
slug: 'zhivan',
|
||||
isActive: true,
|
||||
});
|
||||
em.persist(restaurant);
|
||||
}
|
||||
|
||||
const booteRestaurant = await em.findOne(Restaurant, { slug: 'boote' });
|
||||
if (!booteRestaurant) {
|
||||
const restaurant = em.create(Restaurant, {
|
||||
name: 'بوته',
|
||||
slug: 'boote',
|
||||
isActive: true,
|
||||
});
|
||||
em.persist(restaurant);
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
|
||||
// Get restaurants after flush
|
||||
const zhivan = await em.findOne(Restaurant, { slug: 'zhivan' });
|
||||
const boote = await em.findOne(Restaurant, { slug: 'boote' });
|
||||
|
||||
// 4. Create Categories (Farsi)
|
||||
const categories = [
|
||||
{ title: 'غذای اصلی', restId: zhivan?.id },
|
||||
{ title: 'پیش غذا', restId: zhivan?.id },
|
||||
{ title: 'دسر', restId: zhivan?.id },
|
||||
{ title: 'نوشیدنی', restId: zhivan?.id },
|
||||
{ title: 'غذای اصلی', restId: boote?.id },
|
||||
{ title: 'پیش غذا', restId: boote?.id },
|
||||
{ title: 'دسر', restId: boote?.id },
|
||||
{ title: 'نوشیدنی', restId: boote?.id },
|
||||
];
|
||||
|
||||
const createdCategories: Category[] = [];
|
||||
for (const catData of categories) {
|
||||
const existing = await em.findOne(Category, { title: catData.title, restId: catData.restId });
|
||||
if (!existing) {
|
||||
const category = em.create(Category, {
|
||||
title: catData.title,
|
||||
restId: catData.restId,
|
||||
isActive: true,
|
||||
});
|
||||
em.persist(category);
|
||||
createdCategories.push(category);
|
||||
} else {
|
||||
createdCategories.push(existing);
|
||||
}
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
|
||||
// 5. Create Foods (Farsi)
|
||||
const foods = [
|
||||
// Zhivan Restaurant Foods
|
||||
{
|
||||
title: 'کباب کوبیده',
|
||||
desc: 'کباب کوبیده خوشمزه با برنج و کره',
|
||||
price: 150000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[0]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 50,
|
||||
stockDefault: 50,
|
||||
},
|
||||
{
|
||||
title: 'جوجه کباب',
|
||||
desc: 'جوجه کباب تازه با برنج',
|
||||
price: 120000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[0]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 40,
|
||||
stockDefault: 40,
|
||||
},
|
||||
{
|
||||
title: 'کباب بختیاری',
|
||||
desc: 'کباب بختیاری با برنج و کره',
|
||||
price: 180000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[0]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 35,
|
||||
stockDefault: 35,
|
||||
},
|
||||
{
|
||||
title: 'کباب برگ',
|
||||
desc: 'کباب برگ مرغوب با برنج',
|
||||
price: 160000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[0]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 30,
|
||||
stockDefault: 30,
|
||||
},
|
||||
{
|
||||
title: 'سالاد فصل',
|
||||
desc: 'سالاد تازه با سس مخصوص',
|
||||
price: 35000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[1]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 30,
|
||||
stockDefault: 30,
|
||||
},
|
||||
{
|
||||
title: 'ماست و خیار',
|
||||
desc: 'ماست و خیار تازه',
|
||||
price: 25000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[1]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 25,
|
||||
stockDefault: 25,
|
||||
},
|
||||
{
|
||||
title: 'ترشی',
|
||||
desc: 'ترشی مخلوط خانگی',
|
||||
price: 20000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[1]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 20,
|
||||
stockDefault: 20,
|
||||
},
|
||||
{
|
||||
title: 'بستنی',
|
||||
desc: 'بستنی وانیلی خوشمزه',
|
||||
price: 25000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[2]], // دسر
|
||||
isActive: true,
|
||||
stock: 20,
|
||||
stockDefault: 20,
|
||||
},
|
||||
{
|
||||
title: 'شیرینی',
|
||||
desc: 'شیرینی محلی',
|
||||
price: 30000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[2]], // دسر
|
||||
isActive: true,
|
||||
stock: 15,
|
||||
stockDefault: 15,
|
||||
},
|
||||
{
|
||||
title: 'نوشابه',
|
||||
desc: 'نوشابه گازدار',
|
||||
price: 15000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[3]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 100,
|
||||
stockDefault: 100,
|
||||
},
|
||||
{
|
||||
title: 'دوغ',
|
||||
desc: 'دوغ محلی',
|
||||
price: 20000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[3]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 50,
|
||||
stockDefault: 50,
|
||||
},
|
||||
{
|
||||
title: 'آب معدنی',
|
||||
desc: 'آب معدنی',
|
||||
price: 10000,
|
||||
restaurant: zhivan,
|
||||
categories: [createdCategories[3]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 80,
|
||||
stockDefault: 80,
|
||||
},
|
||||
// Boote Restaurant Foods
|
||||
{
|
||||
title: 'پیتزا مخصوص',
|
||||
desc: 'پیتزا با پنیر و قارچ',
|
||||
price: 180000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[4]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 30,
|
||||
stockDefault: 30,
|
||||
},
|
||||
{
|
||||
title: 'پیتزا پپرونی',
|
||||
desc: 'پیتزا پپرونی تند',
|
||||
price: 200000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[4]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 25,
|
||||
stockDefault: 25,
|
||||
},
|
||||
{
|
||||
title: 'برگر',
|
||||
desc: 'برگر با سیب زمینی سرخ کرده',
|
||||
price: 140000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[4]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 25,
|
||||
stockDefault: 25,
|
||||
},
|
||||
{
|
||||
title: 'برگر مخصوص',
|
||||
desc: 'برگر دوبل با پنیر',
|
||||
price: 180000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[4]], // غذای اصلی
|
||||
isActive: true,
|
||||
stock: 20,
|
||||
stockDefault: 20,
|
||||
},
|
||||
{
|
||||
title: 'سوپ',
|
||||
desc: 'سوپ گرم و خوشمزه',
|
||||
price: 45000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[5]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 15,
|
||||
stockDefault: 15,
|
||||
},
|
||||
{
|
||||
title: 'سالاد سزار',
|
||||
desc: 'سالاد سزار با سس مخصوص',
|
||||
price: 55000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[5]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 20,
|
||||
stockDefault: 20,
|
||||
},
|
||||
{
|
||||
title: 'سیب زمینی سرخ کرده',
|
||||
desc: 'سیب زمینی سرخ کرده ترد',
|
||||
price: 40000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[5]], // پیش غذا
|
||||
isActive: true,
|
||||
stock: 30,
|
||||
stockDefault: 30,
|
||||
},
|
||||
{
|
||||
title: 'کیک شکلاتی',
|
||||
desc: 'کیک شکلاتی خامهای',
|
||||
price: 60000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[6]], // دسر
|
||||
isActive: true,
|
||||
stock: 10,
|
||||
stockDefault: 10,
|
||||
},
|
||||
{
|
||||
title: 'چیزکیک',
|
||||
desc: 'چیزکیک وانیلی',
|
||||
price: 65000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[6]], // دسر
|
||||
isActive: true,
|
||||
stock: 12,
|
||||
stockDefault: 12,
|
||||
},
|
||||
{
|
||||
title: 'نوشابه',
|
||||
desc: 'نوشابه گازدار',
|
||||
price: 15000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[7]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 100,
|
||||
stockDefault: 100,
|
||||
},
|
||||
{
|
||||
title: 'آبمیوه طبیعی',
|
||||
desc: 'آبمیوه تازه',
|
||||
price: 35000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[7]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 40,
|
||||
stockDefault: 40,
|
||||
},
|
||||
{
|
||||
title: 'قهوه',
|
||||
desc: 'قهوه اسپرسو',
|
||||
price: 45000,
|
||||
restaurant: boote,
|
||||
categories: [createdCategories[7]], // نوشیدنی
|
||||
isActive: true,
|
||||
stock: 50,
|
||||
stockDefault: 50,
|
||||
},
|
||||
];
|
||||
|
||||
for (const foodData of foods) {
|
||||
if (foodData.restaurant) {
|
||||
const existing = await em.findOne(Food, {
|
||||
title: foodData.title,
|
||||
restaurant: foodData.restaurant,
|
||||
});
|
||||
if (!existing) {
|
||||
const food = em.create(Food, {
|
||||
title: foodData.title,
|
||||
desc: foodData.desc,
|
||||
price: foodData.price,
|
||||
restaurant: foodData.restaurant,
|
||||
isActive: foodData.isActive,
|
||||
stock: foodData.stock,
|
||||
stockDefault: foodData.stockDefault,
|
||||
sat: false,
|
||||
sun: false,
|
||||
mon: false,
|
||||
breakfast: false,
|
||||
noon: false,
|
||||
dinner: false,
|
||||
discount: 0,
|
||||
rate: 0,
|
||||
inPlaceServe: false,
|
||||
pickupServe: false,
|
||||
});
|
||||
// Add categories
|
||||
if (foodData.categories) {
|
||||
foodData.categories.forEach(cat => food.categories.add(cat));
|
||||
}
|
||||
em.persist(food);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
|
||||
// 6. Create Admins (Farsi)
|
||||
const adminMorteza = await em.findOne(Admin, { phone: '09362532122' });
|
||||
if (!adminMorteza && owner && zhivan) {
|
||||
const admin = em.create(Admin, {
|
||||
phone: '09362532122',
|
||||
firstName: 'مرتضی',
|
||||
lastName: 'مرتضایی',
|
||||
role: owner,
|
||||
restaurant: zhivan,
|
||||
});
|
||||
em.persist(admin);
|
||||
}
|
||||
|
||||
const adminHamid = await em.findOne(Admin, { phone: '09185290775' });
|
||||
if (!adminHamid && accountant && boote) {
|
||||
const admin = em.create(Admin, {
|
||||
phone: '09185290775',
|
||||
firstName: 'حمید',
|
||||
lastName: 'زرگامی',
|
||||
role: accountant,
|
||||
restaurant: boote,
|
||||
});
|
||||
em.persist(admin);
|
||||
}
|
||||
|
||||
await em.flush();
|
||||
|
||||
// 7. Create Users (Farsi)
|
||||
const userMorteza = await em.findOne(User, { phone: '09362532122' });
|
||||
if (!userMorteza && zhivan) {
|
||||
const user = em.create(User, {
|
||||
phone: '09362532122',
|
||||
firstName: 'مرتضی',
|
||||
lastName: 'مرتضایی',
|
||||
restaurant: zhivan,
|
||||
birthDate: new Date('1990-01-01'),
|
||||
marriageDate: new Date('2015-01-01'),
|
||||
isActive: true,
|
||||
gender: true,
|
||||
wallet: 0,
|
||||
points: 0,
|
||||
});
|
||||
em.persist(user);
|
||||
}
|
||||
|
||||
const userHamid = await em.findOne(User, { phone: '09185290775' });
|
||||
if (!userHamid && boote) {
|
||||
const user = em.create(User, {
|
||||
phone: '09185290775',
|
||||
firstName: 'حمید',
|
||||
lastName: 'زرگامی',
|
||||
restaurant: boote,
|
||||
birthDate: new Date('1992-01-01'),
|
||||
marriageDate: new Date('2017-01-01'),
|
||||
isActive: true,
|
||||
gender: true,
|
||||
wallet: 0,
|
||||
points: 0,
|
||||
});
|
||||
em.persist(user);
|
||||
}
|
||||
|
||||
// Final flush
|
||||
await em.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
import { DatabaseSeeder } from './DatabaseSeeder';
|
||||
|
||||
export { DatabaseSeeder };
|
||||
export default DatabaseSeeder;
|
||||
+5
-2
@@ -13,13 +13,16 @@
|
||||
"target": "ES2023",
|
||||
"sourceMap": true,
|
||||
"outDir": "./dist",
|
||||
"baseUrl": "./",
|
||||
"incremental": true,
|
||||
"skipLibCheck": true,
|
||||
"strictNullChecks": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": false,
|
||||
"strictBindCallApply": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
"noFallthroughCasesInSwitch": false,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"src/*": ["./src/*"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user