feat: Product Module (#4161)
* chore: boilerplate setup * wip: add Product, ProductTag, ProductType, ProductCollection models * wip: `IProductService` definition * wip: test function in index, build passing * fix: where condition * chore: get boilerplate working with modules sdk, create a boilerplate test, create product variant model, register services properly * chore: added variant to model * chore: changed definition details + add migrator * cleanup and update product entity * Update product unique index to include soft deleted * Migrations tests * generated migration * update dev orm config * add path aliases * WIP * chore: added boilerplate integration test + database helper + product variant migraiton + model * chore: remove old test utils * update ts and jest config to include path aliases * tweak config * WIP migrations variant * Migrations round * integration tests migrations polishing * chore: fixed issues with test db * fix path aliases when published * use ts-alias * fix connection loader * fixes * wip: product list * (WIP): Data access layer * (WIP): DAL cleanup services * wip: `ProductTag` DAL * wip: `ProductTag` expose list in product service * (WIP): Continue DAL and test list product filtering/populate * WIP: unit tests * chore: added tests for service - productvariant * chore: WIP finding issues with orm manager fork * WIP fix fields selection * chore: make text fixes work * (WIP) product integration * (WIP) product integration * chore: create a product in variant test * list product with relations * wip: `ProductTag` service + integrations * chore: added with and without serialization example * chore: remove only in spec * wip: `ProductCollection` service + integrations * uncomment product.variants * Update type IProductService * (WIP) type work * (WIP) Product variants relation * WIP: replacable data layer * (WIP): Use bundle types * WIP: update type * WIP upadte tests * WIP * wip: options/option values entites * (WIP): cleanup * wip: add option value to variant, fix collection * Integration tests for custom data access layer * update tests * chore: merge with latest branch * chore: scope tests to relations and add category to models/index * chore: ignore dist folders for jest * chore: modularize spec data file * improve DX * module fixture naming * chore: added category tests + fix model * chore: use kebab case * chore: allow scoping products by category id * chore: replace `kebabCase` import * feat: add `deleted_at` to options * improve typings * chore: wip * fix query util * revert webpack * fix: update option models, create option DTOs, tests wip, fix `deduplicateIfNecessary` returning `undefined` * fix: merge conflict * WIP connection * rm unsues deps * fix migrations * fix query util * chore: adds mpath on creation * WIP update types * improve typings * WIP typeings improvement * WIP * deps * chore: package medusa/product ot medusa-commerce/product * chore: added product categories service + descendants filter * add missing index * Add support for strict categories not in * Add support for strict categories not in * lint * rename module * rename module * Create small-ducks-doubt.md * yarn lock * update initialise * chore: fix/finalise DTOs * fix: wrong types in `IProductService` * fix type * Load database config from env if present (#4175) * Load database config from env if present * Load database config from env if present * options optionnal * update util * add defaults * improve filterable interfaces * fix import * fix types * remove medusa-telemetry from modules-sdk * WIP fixing webpack issues when bootstraping module * cleanup * improve loading driver options * cleanup * yarn lock * fix import * improve sdk types and naming * align orther modules initialise method * fix module tests with singleton module * fix module tests with singleton module * add up/down migration scripts * update types * scripts * cleanup migrations and scripts * hash module singleton * cleanup migration * cleanup * fix stringifyCircular usage * improvements * fix deps * fix deps * improve load config utils * improve load config utils * fix deps * add declaration to the build * update yarn * Do not resolve a module path if the exports are explicitly given * fix module registration resolution path when exports are provided. Explicitly check for false and assign an empty string in this scenario for segregation purpose * add comment * fix migration options to prevent set replica errors * chore: update types to a proper depedency * chore: update type package * add seed scripts * Add descriptive error during database config loading * use MedusaError * chore: added lodash to package * add more test to the database config loader util * create bin scripts * add bin * update argv retrieval * update package.json * chore: add product category to injected deps * chore: replace with product category service * move dotenv usage to the functions * do not load db if there is custom manager * chore: fix some tests on products repo * chore: fixed product spec * chore: skip products module on modules register * stringifyCircular update * chore: fix incorrect module resolution * fix: circular stringify and non required module loading * yarn lock * target es5 * chore: mikro-orm back to 5.7.4 * revert module registry * skip external modules * es2020 * update indexes, migration and integration tests * rm only * unit test script should only run unit tests * Exclude product integration from the unit tests and make use of the global integration script to run all packages integration tests * fix integration tests * improve setup * cleanup * log error on setup fail * Create enum like for package names * chore: remove EOL * chore: review part 2 * renamve gateway to productModuleService * chore: added filters and collections to productmoduleservice * chore: add collection to the singleton instance * chore: remove skipped test + add todo * fix indexes on fields and relations + update migration * update yarn lock * update idx * add foreign key * rename interface and add listCategories * rename product module definition --------- Co-authored-by: fPolic <frane@medusajs.com> Co-authored-by: Riqwan Thamir <rmthamir@gmail.com> Co-authored-by: Carlos R. L. Rodrigues <rodrigolr@gmail.com>
This commit is contained in:
committed by
GitHub
parent
ffeeb84d97
commit
14c0f62f84
@@ -0,0 +1,7 @@
|
||||
import { revertMigration } from "../migration-down"
|
||||
|
||||
export default (async () => {
|
||||
const { config } = await import("dotenv")
|
||||
config()
|
||||
await revertMigration()
|
||||
})()
|
||||
@@ -0,0 +1,7 @@
|
||||
import { runMigrations } from "../migration-up"
|
||||
|
||||
export default (async () => {
|
||||
const { config } = await import("dotenv")
|
||||
config()
|
||||
await runMigrations()
|
||||
})()
|
||||
@@ -0,0 +1,17 @@
|
||||
import { run } from "../seed"
|
||||
import { EOL } from "os"
|
||||
|
||||
const args = process.argv
|
||||
const path = args.pop() as string
|
||||
|
||||
export default (async () => {
|
||||
const { config } = await import("dotenv")
|
||||
config()
|
||||
if (!path) {
|
||||
throw new Error(
|
||||
`filePath is required.${EOL}Example: node_modules/@medusajs/product/dist/scripts/bin/run-seed.js <filePath>`
|
||||
)
|
||||
}
|
||||
|
||||
await run({ path })
|
||||
})()
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from "./migration-up"
|
||||
export * from "./migration-down"
|
||||
@@ -0,0 +1,44 @@
|
||||
import { LoaderOptions, Logger } from "@medusajs/types"
|
||||
import {
|
||||
ProductServiceInitializeCustomDataLayerOptions,
|
||||
ProductServiceInitializeOptions,
|
||||
} from "../types"
|
||||
import { createConnection, loadDatabaseConfig } from "../utils"
|
||||
import * as ProductModels from "@models"
|
||||
import { EntitySchema } from "@mikro-orm/core"
|
||||
|
||||
/**
|
||||
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
||||
* he is in charge of reverting the migrations.
|
||||
* @param options
|
||||
* @param logger
|
||||
* @param moduleDeclaration
|
||||
*/
|
||||
export async function revertMigration({
|
||||
options,
|
||||
logger,
|
||||
}: Pick<
|
||||
LoaderOptions<
|
||||
| ProductServiceInitializeOptions
|
||||
| ProductServiceInitializeCustomDataLayerOptions
|
||||
>,
|
||||
"options" | "logger"
|
||||
> = {}) {
|
||||
logger ??= console as unknown as Logger
|
||||
|
||||
const dbData = loadDatabaseConfig(options)
|
||||
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
|
||||
|
||||
const orm = await createConnection(dbData, entities)
|
||||
|
||||
try {
|
||||
const migrator = orm.getMigrator()
|
||||
await migrator.down()
|
||||
|
||||
logger?.info("Product module migration executed")
|
||||
} catch (error) {
|
||||
logger?.error(`Product module migration failed to run - Error: ${error}`)
|
||||
}
|
||||
|
||||
await orm.close()
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import { LoaderOptions, Logger } from "@medusajs/types"
|
||||
import {
|
||||
ProductServiceInitializeCustomDataLayerOptions,
|
||||
ProductServiceInitializeOptions,
|
||||
} from "../types"
|
||||
import { createConnection, loadDatabaseConfig } from "../utils"
|
||||
import * as ProductModels from "@models"
|
||||
import { EntitySchema } from "@mikro-orm/core"
|
||||
|
||||
/**
|
||||
* This script is only valid for mikro orm managers. If a user provide a custom manager
|
||||
* he is in charge of running the migrations.
|
||||
* @param options
|
||||
* @param logger
|
||||
* @param moduleDeclaration
|
||||
*/
|
||||
export async function runMigrations({
|
||||
options,
|
||||
logger,
|
||||
}: Pick<
|
||||
LoaderOptions<
|
||||
| ProductServiceInitializeOptions
|
||||
| ProductServiceInitializeCustomDataLayerOptions
|
||||
>,
|
||||
"options" | "logger"
|
||||
> = {}) {
|
||||
logger ??= console as unknown as Logger
|
||||
|
||||
const dbData = loadDatabaseConfig(options)
|
||||
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
|
||||
|
||||
const orm = await createConnection(dbData, entities)
|
||||
|
||||
try {
|
||||
const migrator = orm.getMigrator()
|
||||
await migrator.up()
|
||||
|
||||
logger?.info("Product module migration executed")
|
||||
} catch (error) {
|
||||
logger?.error(`Product module migration failed to run - Error: ${error}`)
|
||||
}
|
||||
|
||||
await orm.close()
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
import { createConnection, loadDatabaseConfig } from "../utils"
|
||||
import * as ProductModels from "@models"
|
||||
import { Product, ProductCategory, ProductVariant } from "@models"
|
||||
import { EntitySchema } from "@mikro-orm/core"
|
||||
import { LoaderOptions, Logger } from "@medusajs/types"
|
||||
import {
|
||||
ProductServiceInitializeCustomDataLayerOptions,
|
||||
ProductServiceInitializeOptions,
|
||||
} from "../types"
|
||||
import { EOL } from "os"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import { resolve } from "path"
|
||||
|
||||
export async function run({
|
||||
options,
|
||||
logger,
|
||||
path,
|
||||
}: Partial<
|
||||
Pick<
|
||||
LoaderOptions<
|
||||
| ProductServiceInitializeOptions
|
||||
| ProductServiceInitializeCustomDataLayerOptions
|
||||
>,
|
||||
"options" | "logger"
|
||||
>
|
||||
> & {
|
||||
path: string
|
||||
}) {
|
||||
logger?.info(`Loading seed data from ${path}...`)
|
||||
const { productCategoriesData, productsData, variantsData } = await import(
|
||||
resolve(process.cwd(), path)
|
||||
).catch((e) => {
|
||||
logger?.error(
|
||||
`Failed to load seed data from ${path}. Please, provide a relative path and check that you export the following productCategoriesData, productsData, variantsData.${EOL}${e}`
|
||||
)
|
||||
throw e
|
||||
})
|
||||
|
||||
logger ??= console as unknown as Logger
|
||||
|
||||
const dbData = loadDatabaseConfig(options)
|
||||
const entities = Object.values(ProductModels) as unknown as EntitySchema[]
|
||||
|
||||
const orm = await createConnection(dbData, entities)
|
||||
const manager = orm.em.fork()
|
||||
|
||||
try {
|
||||
logger?.info("Inserting product categories, products and variants...")
|
||||
await createProductCategories(manager, productCategoriesData)
|
||||
await createProducts(manager, productsData)
|
||||
await createProductVariants(manager, variantsData)
|
||||
} catch (e) {
|
||||
logger?.error(
|
||||
`Failed to insert the seed data in the PostgreSQL database ${dbData.clientUrl}.${EOL}${e}`
|
||||
)
|
||||
}
|
||||
|
||||
await orm.close(true)
|
||||
}
|
||||
|
||||
async function createProductCategories(
|
||||
manager: SqlEntityManager,
|
||||
categoriesData: any[]
|
||||
): Promise<ProductCategory[]> {
|
||||
const categories: ProductCategory[] = []
|
||||
|
||||
for (let categoryData of categoriesData) {
|
||||
let categoryDataClone = { ...categoryData }
|
||||
let parentCategory: ProductCategory | null = null
|
||||
const parentCategoryId = categoryDataClone.parent_category_id as string
|
||||
delete categoryDataClone.parent_category_id
|
||||
|
||||
if (parentCategoryId) {
|
||||
parentCategory = await manager.findOne(ProductCategory, parentCategoryId)
|
||||
}
|
||||
|
||||
const category = await manager.create(ProductCategory, {
|
||||
...categoryDataClone,
|
||||
parent_category: parentCategory,
|
||||
})
|
||||
|
||||
categories.push(category)
|
||||
}
|
||||
|
||||
await manager.persistAndFlush(categories)
|
||||
|
||||
return categories
|
||||
}
|
||||
|
||||
async function createProducts(manager: SqlEntityManager, data: any[]) {
|
||||
const products: any[] = data.map((productData) => {
|
||||
return manager.create(Product, productData)
|
||||
})
|
||||
|
||||
await manager.persistAndFlush(products)
|
||||
|
||||
return products
|
||||
}
|
||||
|
||||
async function createProductVariants(manager: SqlEntityManager, data: any[]) {
|
||||
const variants: any[] = data.map((variantsData) => {
|
||||
return manager.create(ProductVariant, variantsData)
|
||||
})
|
||||
|
||||
await manager.persistAndFlush(variants)
|
||||
|
||||
return variants
|
||||
}
|
||||
Reference in New Issue
Block a user