feature: add db:create command (#8760)
This commit is contained in:
@@ -51,6 +51,26 @@ export class EnvEditor {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value for an existing key from the
|
||||
* ".env" file
|
||||
*/
|
||||
get(key: string): string | null {
|
||||
const envFile = this.#files.find((file) => file.filePath.endsWith(".env"))
|
||||
if (!envFile) {
|
||||
return null
|
||||
}
|
||||
const matchingLine = envFile.contents.find((line) =>
|
||||
line.startsWith(`${key}=`)
|
||||
)
|
||||
if (!matchingLine) {
|
||||
return null
|
||||
}
|
||||
|
||||
const [_, ...rest] = matchingLine.split("=")
|
||||
return rest.join("=")
|
||||
}
|
||||
|
||||
/**
|
||||
* Set key-value pair to the dot-env files.
|
||||
*
|
||||
|
||||
@@ -26,5 +26,6 @@ export * from "./shipping"
|
||||
export * from "./totals"
|
||||
export * from "./totals/big-number"
|
||||
export * from "./user"
|
||||
export * from "./pg"
|
||||
|
||||
export const MedusaModuleType = Symbol.for("MedusaModule")
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| PostgreSQL utilities
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| @note
|
||||
| These utlities does not rely on an MedusaJS application and neither
|
||||
| uses the Mikro ORM.
|
||||
| The goal here is to run DB operations without booting the application.
|
||||
|
|
||||
| For example:
|
||||
| Creating a database from CLI, or checking if a database exists
|
||||
|
|
||||
*/
|
||||
|
||||
import { Client, type ClientConfig } from "pg"
|
||||
import { parse } from "pg-connection-string"
|
||||
|
||||
/**
|
||||
* Parsers the database connection string into an object
|
||||
* of postgreSQL options
|
||||
*/
|
||||
export function parseConnectionString(connectionString: string) {
|
||||
return parse(connectionString)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a PostgreSQL database client using the connection
|
||||
* string or database options
|
||||
*/
|
||||
export function createClient(options: string | ClientConfig) {
|
||||
return new Client(options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a database using the client. Make sure to call
|
||||
* `client.connect` before using this utility.
|
||||
*/
|
||||
export async function createDb(client: Client, databaseName: string) {
|
||||
await client.query(`CREATE DATABASE "${databaseName}"`)
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a database exists using the Client. Make sure to call
|
||||
* `client.connect` before using this utility.
|
||||
*/
|
||||
export async function dbExists(client: Client, databaseName: string) {
|
||||
const result = await client.query(
|
||||
`SELECT datname FROM pg_catalog.pg_database WHERE datname='${databaseName}';`
|
||||
)
|
||||
return !!result.rowCount
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
import { dropDatabase } from "pg-god"
|
||||
import {
|
||||
createClient,
|
||||
parseConnectionString,
|
||||
dbExists,
|
||||
createDb,
|
||||
} from "../../index"
|
||||
|
||||
const DB_HOST = process.env.DB_HOST ?? "localhost"
|
||||
const DB_USERNAME = process.env.DB_USERNAME ?? ""
|
||||
const DB_PASSWORD = process.env.DB_PASSWORD ?? ""
|
||||
|
||||
export const pgGodCredentials = {
|
||||
user: DB_USERNAME,
|
||||
password: DB_PASSWORD,
|
||||
host: DB_HOST,
|
||||
}
|
||||
|
||||
describe("Pg | createClient", () => {
|
||||
test("create client connection from connection options", async () => {
|
||||
const client = createClient(pgGodCredentials)
|
||||
await client.connect()
|
||||
await client.end()
|
||||
})
|
||||
|
||||
test("create client connection from connectionString without db name", async () => {
|
||||
const client = createClient(
|
||||
`postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}`
|
||||
)
|
||||
await client.connect()
|
||||
await client.end()
|
||||
})
|
||||
|
||||
test("create client connection from connectionString with db name", async () => {
|
||||
const client = createClient(
|
||||
`postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/foo`
|
||||
)
|
||||
await expect(() => client.connect()).rejects.toMatchInlineSnapshot(
|
||||
`[error: database "foo" does not exist]`
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("Pg | parseConnectionString", () => {
|
||||
test("parse connection string without db name", async () => {
|
||||
const options = parseConnectionString(
|
||||
`postgres://${DB_USERNAME}:@${DB_HOST}`
|
||||
)
|
||||
expect(options).toEqual({
|
||||
user: DB_USERNAME,
|
||||
password: "",
|
||||
host: DB_HOST,
|
||||
port: "",
|
||||
database: null,
|
||||
})
|
||||
})
|
||||
|
||||
test("parse connection string with db name", async () => {
|
||||
const options = parseConnectionString(
|
||||
`postgres://${DB_USERNAME}:@${DB_HOST}/foo`
|
||||
)
|
||||
expect(options).toEqual({
|
||||
user: DB_USERNAME,
|
||||
password: "",
|
||||
host: DB_HOST,
|
||||
port: "",
|
||||
database: "foo",
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe("Pg | dbExists", () => {
|
||||
beforeEach(async () => {
|
||||
await dropDatabase({ databaseName: "foo" }, pgGodCredentials)
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await dropDatabase({ databaseName: "foo" }, pgGodCredentials)
|
||||
})
|
||||
|
||||
test("return false when db does not exist", async () => {
|
||||
const options = parseConnectionString(
|
||||
`postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/foo`
|
||||
)
|
||||
const client = createClient({
|
||||
host: options.host!,
|
||||
port: options.port ? Number(options.port) : undefined,
|
||||
user: options.user,
|
||||
password: options.password,
|
||||
})
|
||||
|
||||
await client.connect()
|
||||
const exists = await dbExists(client, options.database!)
|
||||
await client.end()
|
||||
|
||||
expect(exists).toBe(false)
|
||||
})
|
||||
|
||||
test("return true when db exist", async () => {
|
||||
const options = parseConnectionString(
|
||||
`postgres://${DB_USERNAME}:${DB_PASSWORD}@${DB_HOST}/foo`
|
||||
)
|
||||
|
||||
const client = createClient({
|
||||
host: options.host!,
|
||||
port: options.port ? Number(options.port) : undefined,
|
||||
user: options.user,
|
||||
password: options.password,
|
||||
})
|
||||
|
||||
await client.connect()
|
||||
await createDb(client, options.database!)
|
||||
const exists = await dbExists(client, options.database!)
|
||||
await client.end()
|
||||
|
||||
expect(exists).toBe(true)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user