Files
medusa-store/packages/cli/create-medusa-app/src/utils/create-db.ts

240 lines
5.4 KiB
TypeScript

import { EOL } from "os"
import pg from "pg"
import postgresClient, {
DEFAULT_HOST,
DEFAULT_PORT,
} from "./postgres-client.js"
import inquirer from "inquirer"
import logMessage from "./log-message.js"
import formatConnectionString from "./format-connection-string.js"
import { Ora } from "ora"
import { getCurrentOs } from "./get-current-os.js"
type CreateDbOptions = {
client: pg.Client
db: string
}
export default async function createDb({ client, db }: CreateDbOptions) {
await client.query(`CREATE DATABASE "${db}"`)
}
async function doesDbExist(
client: pg.Client,
dbName: string
): Promise<boolean> {
const result = await client.query(
`SELECT datname FROM pg_catalog.pg_database WHERE datname='${dbName}';`
)
return !!result.rowCount
}
export async function runCreateDb({
client,
dbName,
spinner,
}: {
client: pg.Client
dbName: string
spinner: Ora
}): Promise<pg.Client> {
let newClient = client
try {
// create postgres database
await createDb({
client,
db: dbName,
})
// create a new connection with database selected
await client.end()
newClient = await postgresClient({
user: client.user,
password: client.password,
database: dbName,
})
} catch (e) {
spinner.stop()
logMessage({
message: `An error occurred while trying to create your database: ${e}`,
type: "error",
})
}
return newClient
}
async function getForDbName({
dbName,
verbose = false,
}: {
dbName: string
verbose?: boolean
}): Promise<{
client: pg.Client
dbConnectionString: string
dbName: string
}> {
let client!: pg.Client
let postgresUsername = "postgres"
let postgresPassword = ""
const defaultConnectionOptions = {
host: DEFAULT_HOST,
port: DEFAULT_PORT,
}
try {
client = await postgresClient({
user: postgresUsername,
password: postgresPassword,
...defaultConnectionOptions,
})
} catch (e) {
if (verbose) {
logMessage({
message: `The following error occured when connecting to the database: ${e}`,
type: "verbose",
})
}
// ask for the user's postgres credentials
const answers = await inquirer.prompt([
{
type: "input",
name: "postgresUsername",
message: "Enter your Postgres username",
default: "postgres",
validate: (input) => {
return typeof input === "string" && input.length > 0
},
},
{
type: "password",
name: "postgresPassword",
message: "Enter your Postgres password",
},
])
postgresUsername = answers.postgresUsername
postgresPassword = answers.postgresPassword
const { userDbName } = await inquirer.prompt([
{
type: "database",
name: "userDbName",
message: "Enter your Postgres user's database name",
default: answers.postgresUsername,
validate: (input) => {
return typeof input === "string" && input.length > 0
},
},
])
try {
client = await postgresClient({
user: postgresUsername,
password: postgresPassword,
database: userDbName,
...defaultConnectionOptions,
})
} catch (e) {
logMessage({
message: `Couldn't connect to PostgreSQL because of the following error: ${e}.${EOL}${EOL}Make sure you have PostgreSQL installed and the credentials you provided are correct.${EOL}${EOL}If you keep running into this issue despite having PostgreSQL installed, please check out our troubleshooting guidelines: https://docs.medusajs.com/resources/troubleshooting/database-errors`,
type: "error",
})
}
}
// check if database exists
if (await doesDbExist(client, dbName)) {
const { newDbName } = await inquirer.prompt([
{
type: "input",
name: "newDbName",
message: `A database already exists with the name ${dbName}, please enter a name for the database:`,
default: dbName,
validate: (input) => {
return (
typeof input === "string" && input.length > 0 && input !== dbName
)
},
},
])
dbName = newDbName
}
// format connection string
const dbConnectionString = formatConnectionString({
user: postgresUsername,
password: postgresPassword,
host: client!.host,
db: dbName,
})
return {
client,
dbConnectionString,
dbName,
}
}
async function getForDbUrl({
dbUrl,
verbose = false,
}: {
dbUrl: string
verbose?: boolean
}): Promise<{
client: pg.Client
dbConnectionString: string
}> {
let client!: pg.Client
try {
client = await postgresClient({
connectionString: dbUrl,
})
} catch (e) {
if (verbose) {
logMessage({
message: `The following error occured when connecting to the database: ${e}`,
type: "verbose",
})
}
logMessage({
message: `Couldn't connect to PostgreSQL using the database URL you passed. Make sure it's correct and try again.`,
type: "error",
})
}
return {
client,
dbConnectionString: dbUrl,
}
}
export async function getDbClientAndCredentials({
dbName = "",
dbUrl = "",
verbose = false,
}): Promise<{
client: pg.Client
dbConnectionString: string
verbose?: boolean
}> {
if (dbName) {
return await getForDbName({
dbName,
verbose,
})
} else {
return await getForDbUrl({
dbUrl,
verbose,
})
}
}