feat(cli): adds seed script

This commit is contained in:
Sebastian Rindom
2021-06-03 10:03:44 +02:00
parent 42d9a487ff
commit 5136c77401
6 changed files with 160 additions and 52 deletions

View File

@@ -66,6 +66,27 @@ function buildLocalCommands(cli, isLocalProject) {
}
cli
.command({
command: `seed`,
desc: `Migrates and populates the database with the provided file.`,
builder: _ =>
_.option(`f`, {
alias: `seed-file`,
type: `string`,
describe: `Path to the file where the seed is defined.`,
}).option(`m`, {
alias: `migrate`,
type: `boolean`,
default: true,
describe: `Flag to indicate if migrations should be run prior to seeding the database`,
}),
handler: handlerP(
getCommandHandler(`seed`, (args, cmd) => {
process.env.NODE_ENV = process.env.NODE_ENV || `development`
return cmd(args)
})
),
})
.command({
command: `migrations [action]`,
desc: `Migrate the database to the most recent version.`,

View File

@@ -1,5 +1,5 @@
import { createConnection } from "typeorm"
import _ from "lodash"
import { getConfigFile } from "medusa-core-utils"
import Logger from "../loaders/logger"
@@ -13,6 +13,7 @@ const t = async function({ port, directory }) {
const migrationDirs = getMigrations(directory)
const { configModule } = getConfigFile(directory, `medusa-config`)
const connection = await createConnection({
type: configModule.projectConfig.database_type,
url: configModule.projectConfig.database_url,

View File

@@ -1,63 +1,143 @@
import path from "path"
import fs from "fs"
import express from "express"
import { createConnection } from "typeorm"
import { sync as existsSync } from "fs-exists-cached"
import { getConfigFile } from "medusa-core-utils"
const t = async function({ port, directory }) {
const args = process.argv
args.shift()
args.shift()
args.shift()
import Logger from "../loaders/logger"
import loaders from "../loaders"
const { configModule } = getConfigFile(directory, `medusa-config`)
const { plugins } = configModule
import getMigrations from "./utils/get-migrations"
const resolved = plugins.map(plugin => {
if (_.isString(plugin)) {
return resolvePlugin(plugin)
}
const t = async function({ directory, migrate, seedFile }) {
let resolvedPath = seedFile
const details = resolvePlugin(plugin.resolve)
details.options = plugin.options
// If we are already given an absolute path we can skip resolution step
if (!existsSync(resolvedPath)) {
resolvedPath = path.resolve(path.join(directory, seedFile))
return details
})
if (!existsSync(resolvedPath)) {
console.error(`Could not find a seed file at: ${seedFile}`)
console.error(`Resolved path: ${resolvedPath}`)
resolved.push({
resolve: `${directory}/dist`,
name: `project-plugin`,
id: createPluginId(`project-plugin`),
options: {},
version: createFileContentHash(process.cwd(), `**`),
})
const migrationDirs = []
const coreMigrations = path.resolve(__dirname, "../migrations")
migrationDirs.push(`${coreMigrations}/*.js`)
for (const p of resolved) {
const exists = existsSync(`${p.resolve}/migrations`)
if (exists) {
migrationDirs.push(`${p.resolve}/migrations/*.js`)
process.exit(1)
}
}
const connection = await createConnection({
type: configModule.projectConfig.database_type,
url: configModule.projectConfig.database_url,
extra: configModule.projectConfig.database_extra || {},
migrations: migrationDirs,
logging: true,
})
if (migrate) {
const migrationDirs = getMigrations(directory)
const { configModule } = getConfigFile(directory, `medusa-config`)
const connection = await createConnection({
type: configModule.projectConfig.database_type,
url: configModule.projectConfig.database_url,
extra: configModule.projectConfig.database_extra || {},
migrations: migrationDirs,
logging: true,
})
if (args[0] === "run") {
await connection.runMigrations()
await connection.close()
Logger.info("Migrations completed.")
process.exit()
} else if (args[0] === "show") {
const unapplied = await connection.showMigrations()
await connection.close()
process.exit(unapplied ? 1 : 0)
}
const app = express()
const { container } = await loaders({
directory,
expressApp: app,
})
const manager = container.resolve("manager")
const storeService = container.resolve("storeService")
const userService = container.resolve("userService")
const regionService = container.resolve("regionService")
const productService = container.resolve("productService")
const productVariantService = container.resolve("productVariantService")
const shippingOptionService = container.resolve("shippingOptionService")
const shippingProfileService = container.resolve("shippingProfileService")
await manager.transaction(async tx => {
const { store, regions, products, shipping_options, users } = JSON.parse(
fs.readFileSync(resolvedPath, `utf-8`)
)
const gcProfile = await shippingProfileService.retrieveGiftCardDefault()
const defaultProfile = await shippingProfileService.retrieveDefault()
if (store) {
await storeService.withTransaction(tx).update(store)
}
for (const u of users) {
let pass = u.password
if (pass) {
delete u.password
}
await userService.withTransaction(tx).create(u, pass)
}
let regionIds = {}
for (const r of regions) {
let dummyId
if (!r.id || !r.id.startsWith("reg_")) {
dummyId = r.id
delete r.id
}
const reg = await regionService.withTransaction(tx).create(r)
if (dummyId) {
regionIds[dummyId] = reg.id
}
}
for (const so of shipping_options) {
if (regionIds[so.region_id]) {
so.region_id = regionIds[so.region_id]
}
so.profile_id = defaultProfile.id
if (so.is_giftcard) {
so.profile_id = gcProfile.id
delete so.is_giftcard
}
await shippingOptionService.withTransaction(tx).create(so)
}
for (const p of products) {
const variants = p.variants
delete p.variants
p.profile_id = defaultProfile.id
if (p.is_giftcard) {
p.profile_id = gcProfile.id
}
const newProd = await productService.withTransaction(tx).create(p)
if (variants && variants.length) {
const optionIds = p.options.map(
o => newProd.options.find(newO => newO.title === o.title).id
)
for (const v of variants) {
const variant = {
...v,
options: v.options.map((o, index) => ({
...o,
option_id: optionIds[index],
})),
}
await productVariantService
.withTransaction(tx)
.create(newProd.id, variant)
}
}
}
})
}
export default t

View File

@@ -1,5 +1,6 @@
import path from "path"
import fs from "fs"
import { isString } from "lodash"
import { sync as existsSync } from "fs-exists-cached"
import { getConfigFile, createRequireFromPath } from "medusa-core-utils"
@@ -90,7 +91,7 @@ export default directory => {
const { plugins } = configModule
const resolved = plugins.map(plugin => {
if (_.isString(plugin)) {
if (isString(plugin)) {
return resolvePlugin(plugin)
}

View File

@@ -57,6 +57,7 @@ class RegionService extends BaseService {
const cloned = new RegionService({
manager: transactionManager,
regionRepository: this.regionRepository_,
currencyRepository: this.currencyRepository_,
countryRepository: this.countryRepository_,
storeService: this.storeService_,
paymentProviderRepository: this.paymentProviderRepository_,
@@ -114,7 +115,7 @@ class RegionService extends BaseService {
regionObject[key] = value
}
const created = await regionRepository.create(regionObject)
const created = regionRepository.create(regionObject)
const result = await regionRepository.save(created)
return result
})
@@ -253,7 +254,9 @@ class RegionService extends BaseService {
* @param {string} currencyCode - an ISO currency code
*/
async validateCurrency_(currencyCode) {
const store = await this.storeService_.retrieve(["currencies"])
const store = await this.storeService_
.withTransaction(this.transactionManager_)
.retrieve(["currencies"])
const storeCurrencies = store.currencies.map(curr => curr.code)

View File

@@ -319,9 +319,11 @@ class ShippingOptionService extends BaseService {
const optionRepo = manager.getCustomRepository(this.optionRepository_)
const option = await optionRepo.create(data)
const region = await this.regionService_.retrieve(option.region_id, {
relations: ["fulfillment_providers"],
})
const region = await this.regionService_
.withTransaction(manager)
.retrieve(option.region_id, {
relations: ["fulfillment_providers"],
})
if (
!region.fulfillment_providers.find(