chore(): Reorganize modules (#7210)

**What**
Move all modules to the modules directory
This commit is contained in:
Adrien de Peretti
2024-05-02 17:33:34 +02:00
committed by GitHub
parent 7a351eef09
commit 4eae25e1ef
870 changed files with 91 additions and 62 deletions

View File

@@ -0,0 +1,9 @@
export { default as Product } from "./product"
export { default as ProductCategory } from "./product-category"
export { default as ProductCollection } from "./product-collection"
export { default as ProductTag } from "./product-tag"
export { default as ProductType } from "./product-type"
export { default as ProductVariant } from "./product-variant"
export { default as ProductOption } from "./product-option"
export { default as ProductOptionValue } from "./product-option-value"
export { default as Image } from "./product-image"

View File

@@ -0,0 +1,148 @@
import {
DALUtils,
Searchable,
createPsqlIndexStatementHelper,
generateEntityId,
kebabCase,
} from "@medusajs/utils"
import {
BeforeCreate,
Collection,
Entity,
EventArgs,
Filter,
Index,
ManyToMany,
ManyToOne,
OnInit,
OneToMany,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import Product from "./product"
const categoryHandleIndexName = "IDX_category_handle_unique"
const categoryHandleIndexStatement = createPsqlIndexStatementHelper({
name: categoryHandleIndexName,
tableName: "product_category",
columns: ["handle"],
unique: true,
where: "deleted_at IS NULL",
})
const categoryMpathIndexName = "IDX_product_category_path"
const categoryMpathIndexStatement = createPsqlIndexStatementHelper({
name: categoryMpathIndexName,
tableName: "product_category",
columns: ["mpath"],
unique: false,
where: "deleted_at IS NULL",
})
categoryMpathIndexStatement.MikroORMIndex()
categoryHandleIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_category" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductCategory {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text", nullable: false })
name?: string
@Searchable()
@Property({ columnType: "text", default: "", nullable: false })
description?: string
@Searchable()
@Property({ columnType: "text", nullable: false })
handle?: string
@Property({ columnType: "text", nullable: false })
mpath?: string
@Property({ columnType: "boolean", default: false })
is_active?: boolean
@Property({ columnType: "boolean", default: false })
is_internal?: boolean
@Property({ columnType: "numeric", nullable: false, default: 0 })
rank?: number
@ManyToOne(() => ProductCategory, {
columnType: "text",
fieldName: "parent_category_id",
nullable: true,
mapToPk: true,
onDelete: "cascade",
})
parent_category_id?: string | null
@ManyToOne(() => ProductCategory, { nullable: true, persist: false })
parent_category?: ProductCategory
@OneToMany({
entity: () => ProductCategory,
mappedBy: (productCategory) => productCategory.parent_category,
})
category_children = new Collection<ProductCategory>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at?: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at?: Date
@Index({ name: "IDX_product_category_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@ManyToMany(() => Product, (product) => product.categories)
products = new Collection<Product>(this)
@OnInit()
async onInit() {
this.id = generateEntityId(this.id, "pcat")
this.parent_category_id ??= this.parent_category?.id ?? null
}
@BeforeCreate()
async onCreate(args: EventArgs<ProductCategory>) {
this.id = generateEntityId(this.id, "pcat")
this.parent_category_id ??= this.parent_category?.id ?? null
if (!this.handle && this.name) {
this.handle = kebabCase(this.name)
}
const { em } = args
let parentCategory: ProductCategory | null = null
if (this.parent_category_id) {
parentCategory = await em.findOne(
ProductCategory,
this.parent_category_id
)
}
if (parentCategory) {
this.mpath = `${parentCategory?.mpath}${this.id}.`
} else {
this.mpath = `${this.id}.`
}
}
}
export default ProductCategory

View File

@@ -0,0 +1,81 @@
import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
OneToMany,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
kebabCase,
Searchable,
} from "@medusajs/utils"
import Product from "./product"
const collectionHandleIndexName = "IDX_collection_handle_unique"
const collectionHandleIndexStatement = createPsqlIndexStatementHelper({
name: collectionHandleIndexName,
tableName: "product_collection",
columns: ["handle"],
unique: true,
where: "deleted_at IS NULL",
})
collectionHandleIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_collection" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductCollection {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
title: string
@Property({ columnType: "text" })
handle?: string
@OneToMany(() => Product, (product) => product.collection)
products = new Collection<Product>(this)
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_collection_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "pcol")
if (!this.handle && this.title) {
this.handle = kebabCase(this.title)
}
}
}
export default ProductCollection

View File

@@ -0,0 +1,75 @@
import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
ManyToMany,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import Product from "./product"
const imageUrlIndexName = "IDX_product_image_url"
const imageUrlIndexStatement = createPsqlIndexStatementHelper({
name: imageUrlIndexName,
tableName: "image",
columns: ["url"],
unique: false,
where: "deleted_at IS NULL",
})
imageUrlIndexStatement.MikroORMIndex()
@Entity({ tableName: "image" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductImage {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text" })
url: string
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_image_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@ManyToMany(() => Product, (product) => product.images)
products = new Collection<Product>(this)
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "img")
}
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "img")
}
}
export default ProductImage

View File

@@ -0,0 +1,87 @@
import {
DALUtils,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
ManyToMany,
ManyToOne,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { ProductOption, ProductVariant } from "./index"
const optionValueOptionIdIndexName = "IDX_option_value_option_id_unique"
const optionValueOptionIdIndexStatement = createPsqlIndexStatementHelper({
name: optionValueOptionIdIndexName,
tableName: "product_option_value",
columns: ["option_id", "value"],
unique: true,
where: "deleted_at IS NULL",
})
optionValueOptionIdIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_option_value" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductOptionValue {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text" })
value: string
@ManyToOne(() => ProductOption, {
columnType: "text",
fieldName: "option_id",
mapToPk: true,
nullable: true,
onDelete: "cascade",
})
option_id: string | null
@ManyToOne(() => ProductOption, {
nullable: true,
persist: false,
})
option: ProductOption | null
@ManyToMany(() => ProductVariant, (variant) => variant.options)
variants = new Collection<ProductVariant>(this)
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_option_value_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "optval")
this.option_id ??= this.option?.id ?? null
}
}
export default ProductOptionValue

View File

@@ -0,0 +1,93 @@
import {
DALUtils,
Searchable,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Collection,
Entity,
Filter,
Index,
ManyToOne,
OnInit,
OneToMany,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { Product } from "./index"
import ProductOptionValue from "./product-option-value"
const optionProductIdTitleIndexName = "IDX_option_product_id_title_unique"
const optionProductIdTitleIndexStatement = createPsqlIndexStatementHelper({
name: optionProductIdTitleIndexName,
tableName: "product_option",
columns: ["product_id", "title"],
unique: true,
where: "deleted_at IS NULL",
})
optionProductIdTitleIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_option" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductOption {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
title: string
@ManyToOne(() => Product, {
columnType: "text",
fieldName: "product_id",
mapToPk: true,
nullable: true,
onDelete: "cascade",
})
product_id: string | null
@ManyToOne(() => Product, {
persist: false,
nullable: true,
})
product: Product | null
@OneToMany(() => ProductOptionValue, (value) => value.option, {
cascade: [Cascade.PERSIST, "soft-remove" as any],
})
values = new Collection<ProductOptionValue>(this)
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_option_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "opt")
this.product_id ??= this.product?.id ?? null
}
}
export default ProductOption

View File

@@ -0,0 +1,73 @@
import {
BeforeCreate,
Collection,
Entity,
Filter,
Index,
ManyToMany,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
DALUtils,
Searchable,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import Product from "./product"
const tagValueIndexName = "IDX_tag_value_unique"
const tagValueIndexStatement = createPsqlIndexStatementHelper({
name: tagValueIndexName,
tableName: "product_tag",
columns: ["value"],
unique: true,
where: "deleted_at IS NULL",
})
tagValueIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_tag" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductTag {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
value: string
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_tag_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@ManyToMany(() => Product, (product) => product.tags)
products = new Collection<Product>(this)
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "ptag")
}
}
export default ProductTag

View File

@@ -0,0 +1,67 @@
import {
BeforeCreate,
Entity,
Filter,
Index,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
DALUtils,
Searchable,
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
const typeValueIndexName = "IDX_type_value_unique"
const typeValueIndexStatement = createPsqlIndexStatementHelper({
name: typeValueIndexName,
tableName: "product_type",
columns: ["value"],
unique: true,
where: "deleted_at IS NULL",
})
typeValueIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_type" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductType {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
value: string
@Property({ columnType: "json", nullable: true })
metadata?: Record<string, unknown> | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_type_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "ptyp")
}
}
export default ProductType

View File

@@ -0,0 +1,203 @@
import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
optionalNumericSerializer,
Searchable,
} from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Collection,
Entity,
Filter,
Index,
ManyToMany,
ManyToOne,
OneToMany,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { Product, ProductOptionValue } from "@models"
const variantSkuIndexName = "IDX_product_variant_sku_unique"
const variantSkuIndexStatement = createPsqlIndexStatementHelper({
name: variantSkuIndexName,
tableName: "product_variant",
columns: ["sku"],
unique: true,
where: "deleted_at IS NULL",
})
const variantBarcodeIndexName = "IDX_product_variant_barcode_unique"
const variantBarcodeIndexStatement = createPsqlIndexStatementHelper({
name: variantBarcodeIndexName,
tableName: "product_variant",
columns: ["barcode"],
unique: true,
where: "deleted_at IS NULL",
})
const variantEanIndexName = "IDX_product_variant_ean_unique"
const variantEanIndexStatement = createPsqlIndexStatementHelper({
name: variantEanIndexName,
tableName: "product_variant",
columns: ["ean"],
unique: true,
where: "deleted_at IS NULL",
})
const variantUpcIndexName = "IDX_product_variant_upc_unique"
const variantUpcIndexStatement = createPsqlIndexStatementHelper({
name: variantUpcIndexName,
tableName: "product_variant",
columns: ["upc"],
unique: true,
where: "deleted_at IS NULL",
})
const variantProductIdIndexName = "IDX_product_variant_product_id"
const variantProductIdIndexStatement = createPsqlIndexStatementHelper({
name: variantProductIdIndexName,
tableName: "product_variant",
columns: ["product_id"],
unique: false,
where: "deleted_at IS NULL",
})
variantProductIdIndexStatement.MikroORMIndex()
variantSkuIndexStatement.MikroORMIndex()
variantBarcodeIndexStatement.MikroORMIndex()
variantEanIndexStatement.MikroORMIndex()
variantUpcIndexStatement.MikroORMIndex()
@Entity({ tableName: "product_variant" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class ProductVariant {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
title: string
@Searchable()
@Property({ columnType: "text", nullable: true })
sku?: string | null
@Searchable()
@Property({ columnType: "text", nullable: true })
barcode?: string | null
@Searchable()
@Property({ columnType: "text", nullable: true })
ean?: string | null
@Searchable()
@Property({ columnType: "text", nullable: true })
upc?: string | null
// TODO: replace with BigNumber
// Note: Upon serialization, this turns to a string. This is on purpose, because you would loose
// precision if you cast numeric to JS number, as JS number is a float.
// Ref: https://github.com/mikro-orm/mikro-orm/issues/2295
@Property({
columnType: "numeric",
default: 100,
serializer: optionalNumericSerializer,
})
inventory_quantity?: number = 100
@Property({ columnType: "boolean", default: false })
allow_backorder?: boolean = false
@Property({ columnType: "boolean", default: true })
manage_inventory?: boolean = true
@Property({ columnType: "text", nullable: true })
hs_code?: string | null
@Property({ columnType: "text", nullable: true })
origin_country?: string | null
@Property({ columnType: "text", nullable: true })
mid_code?: string | null
@Property({ columnType: "text", nullable: true })
material?: string | null
@Property({ columnType: "numeric", nullable: true })
weight?: number | null
@Property({ columnType: "numeric", nullable: true })
length?: number | null
@Property({ columnType: "numeric", nullable: true })
height?: number | null
@Property({ columnType: "numeric", nullable: true })
width?: number | null
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
// TODO: replace with BigNumber, or in this case a normal int should work
@Property({
columnType: "numeric",
nullable: true,
default: 0,
serializer: optionalNumericSerializer,
})
variant_rank?: number | null
@ManyToOne(() => Product, {
columnType: "text",
nullable: true,
onDelete: "cascade",
fieldName: "product_id",
mapToPk: true,
})
product_id: string | null
@ManyToOne(() => Product, {
persist: false,
nullable: true,
})
product: Product | null
@ManyToMany(() => ProductOptionValue, "variants", {
owner: true,
pivotTable: "product_variant_option",
joinColumn: "variant_id",
inverseJoinColumn: "option_value_id",
})
options = new Collection<ProductOptionValue>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_variant_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "variant")
this.product_id ??= this.product?.id ?? null
}
}
export default ProductVariant

View File

@@ -0,0 +1,224 @@
import {
BeforeCreate,
Collection,
Entity,
Enum,
Filter,
Index,
ManyToMany,
ManyToOne,
OneToMany,
OnInit,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import {
createPsqlIndexStatementHelper,
DALUtils,
generateEntityId,
kebabCase,
ProductUtils,
Searchable,
} from "@medusajs/utils"
import ProductCategory from "./product-category"
import ProductCollection from "./product-collection"
import ProductImage from "./product-image"
import ProductOption from "./product-option"
import ProductTag from "./product-tag"
import ProductType from "./product-type"
import ProductVariant from "./product-variant"
const productHandleIndexName = "IDX_product_handle_unique"
const productHandleIndexStatement = createPsqlIndexStatementHelper({
name: productHandleIndexName,
tableName: "product",
columns: ["handle"],
unique: true,
where: "deleted_at IS NULL",
})
const productTypeIndexName = "IDX_product_type_id"
const productTypeIndexStatement = createPsqlIndexStatementHelper({
name: productTypeIndexName,
tableName: "product",
columns: ["type_id"],
unique: false,
where: "deleted_at IS NULL",
})
const productCollectionIndexName = "IDX_product_collection_id"
const productCollectionIndexStatement = createPsqlIndexStatementHelper({
name: productCollectionIndexName,
tableName: "product",
columns: ["collection_id"],
unique: false,
where: "deleted_at IS NULL",
})
productTypeIndexStatement.MikroORMIndex()
productCollectionIndexStatement.MikroORMIndex()
productHandleIndexStatement.MikroORMIndex()
@Entity({ tableName: "product" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
class Product {
@PrimaryKey({ columnType: "text" })
id!: string
@Searchable()
@Property({ columnType: "text" })
title: string
@Property({ columnType: "text" })
handle?: string
@Searchable()
@Property({ columnType: "text", nullable: true })
subtitle?: string | null
@Searchable()
@Property({
columnType: "text",
nullable: true,
})
description?: string | null
@Property({ columnType: "boolean", default: false })
is_giftcard!: boolean
@Enum(() => ProductUtils.ProductStatus)
@Property({ default: ProductUtils.ProductStatus.DRAFT })
status!: ProductUtils.ProductStatus
@Property({ columnType: "text", nullable: true })
thumbnail?: string | null
@OneToMany(() => ProductOption, (o) => o.product, {
cascade: ["soft-remove"] as any,
})
options = new Collection<ProductOption>(this)
@Searchable()
@OneToMany(() => ProductVariant, (variant) => variant.product, {
cascade: ["soft-remove"] as any,
})
variants = new Collection<ProductVariant>(this)
@Property({ columnType: "text", nullable: true })
weight?: number | null
@Property({ columnType: "text", nullable: true })
length?: number | null
@Property({ columnType: "text", nullable: true })
height?: number | null
@Property({ columnType: "text", nullable: true })
width?: number | null
@Property({ columnType: "text", nullable: true })
origin_country?: string | null
@Property({ columnType: "text", nullable: true })
hs_code?: string | null
@Property({ columnType: "text", nullable: true })
mid_code?: string | null
@Property({ columnType: "text", nullable: true })
material?: string | null
@Searchable()
@ManyToOne(() => ProductCollection, {
columnType: "text",
nullable: true,
fieldName: "collection_id",
mapToPk: true,
onDelete: "set null",
})
collection_id: string | null
@ManyToOne(() => ProductCollection, {
nullable: true,
persist: false,
})
collection: ProductCollection | null
@ManyToOne(() => ProductType, {
columnType: "text",
nullable: true,
fieldName: "type_id",
mapToPk: true,
onDelete: "set null",
})
type_id: string | null
@ManyToOne(() => ProductType, {
nullable: true,
persist: false,
})
type: ProductType | null
@ManyToMany(() => ProductTag, "products", {
owner: true,
pivotTable: "product_tags",
index: "IDX_product_tag_id",
})
tags = new Collection<ProductTag>(this)
@ManyToMany(() => ProductImage, "products", {
owner: true,
pivotTable: "product_images",
joinColumn: "product_id",
inverseJoinColumn: "image_id",
})
images = new Collection<ProductImage>(this)
@ManyToMany(() => ProductCategory, "products", {
owner: true,
pivotTable: "product_category_product",
})
categories = new Collection<ProductCategory>(this)
@Property({ columnType: "boolean", default: true })
discountable: boolean
@Property({ columnType: "text", nullable: true })
external_id?: string | null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Index({ name: "IDX_product_deleted_at" })
@Property({ columnType: "timestamptz", nullable: true })
deleted_at?: Date
@Property({ columnType: "jsonb", nullable: true })
metadata?: Record<string, unknown> | null
@OnInit()
@BeforeCreate()
onInit() {
this.id = generateEntityId(this.id, "prod")
this.type_id ??= this.type?.id ?? null
this.collection_id ??= this.collection?.id ?? null
if (!this.handle && this.title) {
this.handle = kebabCase(this.title)
}
}
}
export default Product