create database structure
This commit is contained in:
parent
e5b5d7e67d
commit
ad6ee64565
15 changed files with 483 additions and 14 deletions
|
|
@ -2,7 +2,6 @@ import "reflect-metadata";
|
||||||
import { DataSource } from "typeorm";
|
import { DataSource } from "typeorm";
|
||||||
|
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
import { UserEntity } from "./entities/UserEntity.js";
|
|
||||||
|
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
import { dirname, join } from "path";
|
import { dirname, join } from "path";
|
||||||
|
|
@ -26,7 +25,7 @@ export const AppDataSource = new DataSource({
|
||||||
synchronize: NODE_ENV === "dev" ? false : false,
|
synchronize: NODE_ENV === "dev" ? false : false,
|
||||||
//logging logs sql command on the terminal
|
//logging logs sql command on the terminal
|
||||||
logging: NODE_ENV === "dev" ? false : false,
|
logging: NODE_ENV === "dev" ? false : false,
|
||||||
entities: [join(__dirname, "/entities/*.{ts,js}")],
|
entities: [join(__dirname, "/entities/*.{js, ts}")],
|
||||||
migrations: [join(__dirname, "/migrations/*.{ts,js}")],
|
migrations: [join(__dirname, "/migrations/*.js")],
|
||||||
subscribers: [],
|
subscribers: [],
|
||||||
});
|
});
|
||||||
|
|
@ -8,9 +8,9 @@ export abstract class AbstractEntity {
|
||||||
@PrimaryGeneratedColumn("uuid")
|
@PrimaryGeneratedColumn("uuid")
|
||||||
id?: string;
|
id?: string;
|
||||||
|
|
||||||
@CreateDateColumn()
|
@CreateDateColumn({name: "create_date"})
|
||||||
createdAt?: Date;
|
createDate?: Date;
|
||||||
|
|
||||||
@UpdateDateColumn()
|
@UpdateDateColumn({name: "update_date"})
|
||||||
updatedAt?: Date;
|
updateDate?: Date;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
31
src/entities/RecipeEntity.ts
Normal file
31
src/entities/RecipeEntity.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { Entity, Column, OneToMany, Relation } from "typeorm";
|
||||||
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
import { RecipeInstructionStepEntity } from "./RecipeInstructionStepEntity.js";
|
||||||
|
import { RecipeIngredientGroupEntity } from "./RecipeIngredientGroupEntity.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity describing a recipe
|
||||||
|
*/
|
||||||
|
@Entity({ name: "recipe" })
|
||||||
|
export class RecipeEntity extends AbstractEntity {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
title!: string;
|
||||||
|
|
||||||
|
@Column({ nullable: true })
|
||||||
|
amount?: number;
|
||||||
|
|
||||||
|
@Column({ nullable: true, name: "amount_description" })
|
||||||
|
amountDescription?: string;
|
||||||
|
|
||||||
|
// make sure not to induce a circular dependency! user arrow function without brackets!
|
||||||
|
@OneToMany(() => RecipeInstructionStepEntity, (instructionStep) => instructionStep.recipe, {
|
||||||
|
cascade: true,
|
||||||
|
})
|
||||||
|
instructionSteps!: RecipeInstructionStepEntity[];
|
||||||
|
|
||||||
|
// make sure not to induce a circular dependency! user arrow function without brackets!
|
||||||
|
@OneToMany(() => RecipeIngredientGroupEntity, (ingredientGroup) => ingredientGroup.recipe, {
|
||||||
|
cascade: true,
|
||||||
|
})
|
||||||
|
ingredientGroups!: Relation<RecipeIngredientGroupEntity>[];
|
||||||
|
}
|
||||||
20
src/entities/RecipeIngredientEntity.ts
Normal file
20
src/entities/RecipeIngredientEntity.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Column, Entity, ManyToOne, Relation} from "typeorm";
|
||||||
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
import { RecipeIngredientGroupEntity } from "./RecipeIngredientGroupEntity.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity describing an ingredient group for a recipe
|
||||||
|
*/
|
||||||
|
@Entity({ name: "recipe_ingredient" })
|
||||||
|
export class RecipeIngredientEntity extends AbstractEntity {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
title!: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
sortOrder!: number;
|
||||||
|
|
||||||
|
@ManyToOne(() => RecipeIngredientGroupEntity, (ingredientGroup) => ingredientGroup.ingredients,
|
||||||
|
{onDelete: "CASCADE"}
|
||||||
|
)
|
||||||
|
ingredientGroup!: Relation<RecipeIngredientGroupEntity>;
|
||||||
|
}
|
||||||
27
src/entities/RecipeIngredientGroupEntity.ts
Normal file
27
src/entities/RecipeIngredientGroupEntity.ts
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { Column, Entity, ManyToOne, OneToMany, Relation} from "typeorm";
|
||||||
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
import { RecipeEntity } from "./RecipeEntity.js";
|
||||||
|
import { RecipeIngredientEntity } from "./RecipeIngredientEntity.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity describing an ingredient group for a recipe
|
||||||
|
*/
|
||||||
|
@Entity({ name: "recipe_ingredient_group" })
|
||||||
|
export class RecipeIngredientGroupEntity extends AbstractEntity {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
title!: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
sortOrder!: number;
|
||||||
|
|
||||||
|
@ManyToOne(() => RecipeEntity, (recipe) => recipe.ingredientGroups,
|
||||||
|
{onDelete: "CASCADE"}
|
||||||
|
)
|
||||||
|
recipe!: Relation<RecipeEntity>;
|
||||||
|
|
||||||
|
@OneToMany(() => RecipeIngredientEntity, (ingredient) => ingredient.ingredientGroup, {
|
||||||
|
cascade: true,
|
||||||
|
})
|
||||||
|
ingredients!: Relation<RecipeIngredientEntity>[];
|
||||||
|
|
||||||
|
}
|
||||||
21
src/entities/RecipeInstructionStepEntity.ts
Normal file
21
src/entities/RecipeInstructionStepEntity.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { Column, Entity, ManyToOne, Relation} from "typeorm";
|
||||||
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
import { RecipeEntity } from "./RecipeEntity.js";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Entity describing an instruction step for a recipe
|
||||||
|
*/
|
||||||
|
@Entity({ name: "recipe_instruction_step" })
|
||||||
|
export class RecipeInstructionStepEntity extends AbstractEntity {
|
||||||
|
@Column({ nullable: false })
|
||||||
|
text!: string;
|
||||||
|
|
||||||
|
@Column({ nullable: false })
|
||||||
|
sortOrder!: number;
|
||||||
|
|
||||||
|
@ManyToOne(() => RecipeEntity, (recipe) => recipe.instructionSteps,
|
||||||
|
{onDelete: "CASCADE"}
|
||||||
|
)
|
||||||
|
recipe!: Relation<RecipeEntity>;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
import { Entity, Column } from "typeorm";
|
import { Entity, Column } from "typeorm";
|
||||||
import { AbstractEntity } from "./AbstractEntity.js";
|
import { AbstractEntity } from "./AbstractEntity.js";
|
||||||
|
|
||||||
|
// @todo Add migration to update table
|
||||||
@Entity({ name: "user" })
|
@Entity({ name: "user" })
|
||||||
export class UserEntity extends AbstractEntity {
|
export class UserEntity extends AbstractEntity {
|
||||||
@Column({ nullable: false })
|
@Column({ nullable: false, name: "user_name" })
|
||||||
userName!: string;
|
userName!: string;
|
||||||
|
|
||||||
@Column({ nullable: false })
|
@Column({ nullable: false })
|
||||||
|
|
@ -12,10 +13,10 @@ export class UserEntity extends AbstractEntity {
|
||||||
@Column({ nullable: false })
|
@Column({ nullable: false })
|
||||||
password!: string;
|
password!: string;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true, name: "first_name"})
|
||||||
firstName?: string;
|
firstName?: string;
|
||||||
|
|
||||||
@Column({ nullable: true })
|
@Column({ nullable: true, name: "last_name"})
|
||||||
lastName?: string;
|
lastName?: string;
|
||||||
|
|
||||||
@Column({ default: "user" })
|
@Column({ default: "user" })
|
||||||
|
|
|
||||||
|
|
@ -16,11 +16,13 @@ app.use(errorHandler);
|
||||||
|
|
||||||
async function startServer() {
|
async function startServer() {
|
||||||
try {
|
try {
|
||||||
|
console.log("starting server")
|
||||||
// Initialize database
|
// Initialize database
|
||||||
await AppDataSource.initialize();
|
await AppDataSource.initialize();
|
||||||
console.log("Data Source initialized");
|
console.log("Data Source initialized");
|
||||||
|
|
||||||
// Run pending migrations
|
// Run pending migrations
|
||||||
|
console.log(AppDataSource.migrations);
|
||||||
await AppDataSource.runMigrations();
|
await AppDataSource.runMigrations();
|
||||||
console.log("Migrations executed");
|
console.log("Migrations executed");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,8 @@ export abstract class AbstractDtoEntityMapper<
|
||||||
*/
|
*/
|
||||||
protected mapBaseEntityToDto(entity: E, dto: D): D {
|
protected mapBaseEntityToDto(entity: E, dto: D): D {
|
||||||
dto.id = entity.id;
|
dto.id = entity.id;
|
||||||
dto.createdAt = entity.createdAt;
|
dto.createdAt = entity.createDate;
|
||||||
dto.updatedAt = entity.updatedAt;
|
dto.updatedAt = entity.updateDate;
|
||||||
return dto;
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -20,8 +20,8 @@ export abstract class AbstractDtoEntityMapper<
|
||||||
*/
|
*/
|
||||||
protected mapBaseDtoToEntity(dto: D, entity: E): E {
|
protected mapBaseDtoToEntity(dto: D, entity: E): E {
|
||||||
entity.id = dto.id;
|
entity.id = dto.id;
|
||||||
entity.createdAt = dto.createdAt;
|
entity.createDate = dto.createdAt;
|
||||||
entity.updatedAt = dto.updatedAt;
|
entity.updateDate = dto.updatedAt;
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
83
src/migrations/1758958856261-RenameUserColumns.ts
Normal file
83
src/migrations/1758958856261-RenameUserColumns.ts
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { MigrationInterface, QueryRunner, TableUnique } from "typeorm";
|
||||||
|
|
||||||
|
export class RenameUserColumns1758958856261 implements MigrationInterface {
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// drop constraint
|
||||||
|
await queryRunner.dropUniqueConstraint("user", "UQ_user_userName");
|
||||||
|
// rename columns
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"userName",
|
||||||
|
"user_name"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"firstName",
|
||||||
|
"first_name"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"lastName",
|
||||||
|
"last_name"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"createdAt",
|
||||||
|
"create_date"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"updatedAt",
|
||||||
|
"update_date"
|
||||||
|
)
|
||||||
|
// Add a unique constraint on user_name
|
||||||
|
await queryRunner.createUniqueConstraint(
|
||||||
|
"user",
|
||||||
|
new TableUnique({
|
||||||
|
columnNames: ["user_name"],
|
||||||
|
name: "UQ_user_user_name",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// drop constraint
|
||||||
|
await queryRunner.dropUniqueConstraint("user", "UQ_user_user_name");
|
||||||
|
// rename columns
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"user_name",
|
||||||
|
"userName",
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"first_name",
|
||||||
|
"firstName"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"last_name",
|
||||||
|
"lastName"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"create_date",
|
||||||
|
"createdAt"
|
||||||
|
)
|
||||||
|
await queryRunner.renameColumn(
|
||||||
|
"user",
|
||||||
|
"update_date",
|
||||||
|
"updatedAt"
|
||||||
|
)
|
||||||
|
// Add a unique constraint on userName
|
||||||
|
await queryRunner.createUniqueConstraint(
|
||||||
|
"user",
|
||||||
|
new TableUnique({
|
||||||
|
columnNames: ["userName"],
|
||||||
|
name: "UQ_user_userName",
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
48
src/migrations/1758959405239-CreateRecipeTable.ts
Normal file
48
src/migrations/1758959405239-CreateRecipeTable.ts
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
import { MigrationInterface, QueryRunner, Table } from "typeorm";
|
||||||
|
|
||||||
|
export class CreateRecipeTable1758959405239 implements MigrationInterface {
|
||||||
|
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Create table
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "recipe",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
type: "uuid",
|
||||||
|
isPrimary: true,
|
||||||
|
isGenerated: true,
|
||||||
|
generationStrategy: "uuid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "amount",
|
||||||
|
type: "varchar",
|
||||||
|
isNullable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "amount_description",
|
||||||
|
type: "varchar",
|
||||||
|
isNullable: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Drop the table
|
||||||
|
await queryRunner.dropTable("recipe");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import {
|
||||||
|
MigrationInterface,
|
||||||
|
QueryRunner,
|
||||||
|
Table,
|
||||||
|
TableForeignKey,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
export class CreateRecipeIngredientGroupTable1758959437946
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Create table
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "recipe_ingredient_group",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
type: "uuid",
|
||||||
|
isPrimary: true,
|
||||||
|
isGenerated: true,
|
||||||
|
generationStrategy: "uuid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
type: "varchar",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sortOrder",
|
||||||
|
type: "int",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "recipe_id", // foreign key column
|
||||||
|
type: "uuid",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add foreign key to recipe table
|
||||||
|
await queryRunner.createForeignKey(
|
||||||
|
"recipe_ingredient_group",
|
||||||
|
new TableForeignKey({
|
||||||
|
columnNames: ["recipe_id"],
|
||||||
|
referencedTableName: "recipe",
|
||||||
|
referencedColumnNames: ["id"],
|
||||||
|
onDelete: "CASCADE", // delete ingredient groups if recipe is deleted
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Drop foreign key first
|
||||||
|
const table = await queryRunner.getTable("recipe_ingredient_group");
|
||||||
|
const foreignKey = table?.foreignKeys.find(
|
||||||
|
(fk) => fk.columnNames.indexOf("recipe_id") !== -1
|
||||||
|
);
|
||||||
|
if (foreignKey) {
|
||||||
|
await queryRunner.dropForeignKey("recipe_ingredient_group", foreignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop table
|
||||||
|
await queryRunner.dropTable("recipe_ingredient_group");
|
||||||
|
}
|
||||||
|
}
|
||||||
79
src/migrations/1758959442589-CreateRecipeIngredientTable.ts
Normal file
79
src/migrations/1758959442589-CreateRecipeIngredientTable.ts
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
import {
|
||||||
|
MigrationInterface,
|
||||||
|
QueryRunner,
|
||||||
|
Table,
|
||||||
|
TableForeignKey,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
export class CreateRecipeIngredientTable1758959442589
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Create table
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "recipe_ingredient",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
type: "uuid",
|
||||||
|
isPrimary: true,
|
||||||
|
isGenerated: true,
|
||||||
|
generationStrategy: "uuid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "title",
|
||||||
|
type: "varchar",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sortOrder",
|
||||||
|
type: "int",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "recipe_ingredient_group_id", // foreign key column
|
||||||
|
type: "uuid",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add foreign key to recipe table
|
||||||
|
await queryRunner.createForeignKey(
|
||||||
|
"recipe_ingredient",
|
||||||
|
new TableForeignKey({
|
||||||
|
columnNames: ["recipe_ingredient_group_id"],
|
||||||
|
referencedTableName: "recipe_ingredient_group",
|
||||||
|
referencedColumnNames: ["id"],
|
||||||
|
onDelete: "CASCADE", // delete ingredient if ingredient_group is deleted
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Drop foreign key first
|
||||||
|
const table = await queryRunner.getTable("recipe_ingredient");
|
||||||
|
const foreignKey = table?.foreignKeys.find(
|
||||||
|
(fk) => fk.columnNames.indexOf("recipe_ingredient_group_id") !== -1
|
||||||
|
);
|
||||||
|
if (foreignKey) {
|
||||||
|
await queryRunner.dropForeignKey("recipe_ingredient", foreignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop table
|
||||||
|
await queryRunner.dropTable("recipe_ingredient");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
import {
|
||||||
|
MigrationInterface,
|
||||||
|
QueryRunner,
|
||||||
|
Table,
|
||||||
|
TableForeignKey,
|
||||||
|
} from "typeorm";
|
||||||
|
|
||||||
|
export class CreateRecipeInstructionStepTable1758959460127
|
||||||
|
implements MigrationInterface
|
||||||
|
{
|
||||||
|
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Create table
|
||||||
|
await queryRunner.createTable(
|
||||||
|
new Table({
|
||||||
|
name: "recipe_instruction_step",
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
type: "uuid",
|
||||||
|
isPrimary: true,
|
||||||
|
isGenerated: true,
|
||||||
|
generationStrategy: "uuid",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "create_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "update_date",
|
||||||
|
type: "timestamp",
|
||||||
|
default: "now()",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "text",
|
||||||
|
type: "varchar",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "sortOrder",
|
||||||
|
type: "int",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "recipe_id", // foreign key column
|
||||||
|
type: "uuid",
|
||||||
|
isNullable: false,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
// Add foreign key to recipe table
|
||||||
|
await queryRunner.createForeignKey(
|
||||||
|
"recipe_instruction_step",
|
||||||
|
new TableForeignKey({
|
||||||
|
columnNames: ["recipe_id"],
|
||||||
|
referencedTableName: "recipe",
|
||||||
|
referencedColumnNames: ["id"],
|
||||||
|
onDelete: "CASCADE", // delete instruction steps if recipe is deleted
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||||
|
// Drop foreign key first
|
||||||
|
const table = await queryRunner.getTable("recipe_instruction_step");
|
||||||
|
const foreignKey = table?.foreignKeys.find(
|
||||||
|
(fk) => fk.columnNames.indexOf("recipe_id") !== -1
|
||||||
|
);
|
||||||
|
if (foreignKey) {
|
||||||
|
await queryRunner.dropForeignKey("recipe_instruction_step", foreignKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Drop table
|
||||||
|
await queryRunner.dropTable("recipe_instruction_step");
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue