From 6273b4b160493463e1199e5db4e9cfa4cff6fbe4 Mon Sep 17 00:00:00 2001 From: Adrien de Peretti Date: Mon, 11 Sep 2023 12:10:40 +0200 Subject: [PATCH] feat(utils, module-sdk, medusa): Extract pg connection utils to utils package (#4961) --- .changeset/giant-paws-change.md | 8 +++ packages/medusa/package.json | 1 - packages/medusa/src/loaders/pg-connection.ts | 62 +++++++------------ packages/modules-sdk/src/medusa-app.ts | 54 ++++++---------- packages/types/src/modules-sdk/index.ts | 1 + packages/utils/package.json | 1 + .../mikro-orm/mikro-orm-create-connection.ts | 1 + .../src/modules-sdk/create-pg-connection.ts | 30 +++++++++ packages/utils/src/modules-sdk/index.ts | 1 + yarn.lock | 2 +- 10 files changed, 85 insertions(+), 76 deletions(-) create mode 100644 .changeset/giant-paws-change.md create mode 100644 packages/utils/src/modules-sdk/create-pg-connection.ts diff --git a/.changeset/giant-paws-change.md b/.changeset/giant-paws-change.md new file mode 100644 index 0000000000..74f254da0b --- /dev/null +++ b/.changeset/giant-paws-change.md @@ -0,0 +1,8 @@ +--- +"@medusajs/medusa": patch +"@medusajs/modules-sdk": patch +"@medusajs/types": patch +"@medusajs/utils": patch +--- + +feat(utils, module-sdk, medusa, types): Extract pg connection utils to utils package diff --git a/packages/medusa/package.json b/packages/medusa/package.json index 872e9a3aa0..918ee4ab69 100644 --- a/packages/medusa/package.json +++ b/packages/medusa/package.json @@ -74,7 +74,6 @@ "ioredis-mock": "8.4.0", "iso8601-duration": "^1.3.0", "jsonwebtoken": "^9.0.0", - "knex": "2.4.2", "lodash": "^4.17.21", "medusa-core-utils": "^1.2.0", "medusa-telemetry": "^0.0.17", diff --git a/packages/medusa/src/loaders/pg-connection.ts b/packages/medusa/src/loaders/pg-connection.ts index 1a5cd10e4f..b522b2155a 100644 --- a/packages/medusa/src/loaders/pg-connection.ts +++ b/packages/medusa/src/loaders/pg-connection.ts @@ -1,8 +1,6 @@ import { asValue, AwilixContainer } from "awilix" import { ConfigModule } from "../types/global" -import { ContainerRegistrationKeys } from "@medusajs/utils" -import { ClientConfig } from "pg" -import knex from "knex" +import { ContainerRegistrationKeys, ModulesSdkUtils } from "@medusajs/utils" type Options = { configModule: ConfigModule @@ -10,44 +8,32 @@ type Options = { } export default async ({ container, configModule }: Options): Promise => { - const connectionString = configModule.projectConfig.database_url - const database = configModule.projectConfig.database_database - const extra: any = configModule.projectConfig.database_extra || {} - const schema = configModule.projectConfig.database_schema || "public" + if (container.hasRegistration(ContainerRegistrationKeys.PG_CONNECTION)) { + return + } // Share a knex connection to be consumed by the shared modules - if (!container.hasRegistration(ContainerRegistrationKeys.PG_CONNECTION)) { - const config: ClientConfig = { - connectionString, - database, - ssl: extra?.ssl ?? false, - idle_in_transaction_session_timeout: - extra.idle_in_transaction_session_timeout ?? undefined, // prevent null to be passed - } + const connectionString = configModule.projectConfig.database_url + const extra: any = configModule.projectConfig.database_extra || {} + const schema = configModule.projectConfig.database_schema || "public" + const idleTimeoutMillis = extra.idleTimeoutMillis ?? undefined // prevent null to be passed + const poolMax = extra.max - // TODO: see later if it is possible to use the same connection with multiple pool config using this shared connection across the modules - // const pgConnection = await new Client(config).connect() // or any other method to create your connection here + delete extra.max + delete extra.idleTimeoutMillis - const pgConnection = knex({ - client: "pg", - searchPath: schema, - connection: { - connectionString: connectionString, - database, - ssl: extra?.ssl ?? false, - idle_in_transaction_session_timeout: - extra.idle_in_transaction_session_timeout ?? undefined, // prevent null to be passed - }, - pool: { - min: 0, - max: extra.max, - idleTimeoutMillis: extra.idleTimeoutMillis ?? undefined, // prevent null to be passed - }, - }) + const pgConnection = ModulesSdkUtils.createPgConnection({ + clientUrl: connectionString, + schema, + driverOptions: extra, + pool: { + max: poolMax, + idleTimeoutMillis, + }, + }) - container.register( - ContainerRegistrationKeys.PG_CONNECTION, - asValue(pgConnection) - ) - } + container.register( + ContainerRegistrationKeys.PG_CONNECTION, + asValue(pgConnection) + ) } diff --git a/packages/modules-sdk/src/medusa-app.ts b/packages/modules-sdk/src/medusa-app.ts index 2ba2686884..3af54e22ce 100644 --- a/packages/modules-sdk/src/medusa-app.ts +++ b/packages/modules-sdk/src/medusa-app.ts @@ -10,8 +10,8 @@ import { } from "@medusajs/types" import { ContainerRegistrationKeys, - ModulesSdkUtils, isObject, + ModulesSdkUtils, } from "@medusajs/utils" import { MODULE_PACKAGE_NAMES, Modules } from "./definitions" import { MedusaModule } from "./medusa-module" @@ -19,21 +19,12 @@ import { RemoteLink } from "./remote-link" import { RemoteQuery } from "./remote-query" export type MedusaModuleConfig = (Partial | Modules)[] -export type SharedResources = { - database?: ModuleServiceInitializeOptions["database"] & { - pool?: { - name?: string - afterCreate?: Function - min?: number - max?: number - refreshIdle?: boolean - idleTimeoutMillis?: number - reapIntervalMillis?: number - returnToHead?: boolean - priorityRange?: number - log?: (message: string, logLevel: string) => void - } - } +type SharedResources = { + database?: ModuleServiceInitializeOptions["database"] +} + +const isModuleConfig = (obj: any): obj is ModuleConfig => { + return isObject(obj) } export async function MedusaApp({ @@ -77,25 +68,16 @@ export async function MedusaApp({ sharedResourcesConfig as ModuleServiceInitializeOptions, true )! - const { pool } = sharedResourcesConfig?.database ?? {} - if (dbData?.clientUrl) { - const { knex } = await import("knex") - const dbConnection = knex({ - client: "pg", - searchPath: dbData.schema || "public", - connection: { - connectionString: dbData.clientUrl, - ssl: (dbData.driverOptions?.connection as any).ssl! ?? false, - }, - pool: { - // https://knexjs.org/guide/#pool - ...(pool ?? {}), - min: pool?.min ?? 0, - }, - }) - - injectedDependencies[ContainerRegistrationKeys.PG_CONNECTION] = dbConnection + if ( + dbData.clientUrl && + !injectedDependencies[ContainerRegistrationKeys.PG_CONNECTION] + ) { + injectedDependencies[ContainerRegistrationKeys.PG_CONNECTION] = + ModulesSdkUtils.createPgConnection({ + ...(sharedResourcesConfig?.database ?? {}), + ...dbData, + }) } const allModules: Record = {} @@ -106,7 +88,7 @@ export async function MedusaApp({ let path: string let declaration: any = {} - if (isObject(mod)) { + if (isModuleConfig(mod)) { if (!mod.module) { throw new Error( `Module ${JSON.stringify(mod)} is missing module name.` @@ -141,7 +123,7 @@ export async function MedusaApp({ declaration, undefined, injectedDependencies, - isObject(mod) ? mod.definition : undefined + isModuleConfig(mod) ? mod.definition : undefined )) as LoadedModule if (allModules[key] && !Array.isArray(allModules[key])) { diff --git a/packages/types/src/modules-sdk/index.ts b/packages/types/src/modules-sdk/index.ts index 21de0d01bb..f3e2b62b2e 100644 --- a/packages/types/src/modules-sdk/index.ts +++ b/packages/types/src/modules-sdk/index.ts @@ -202,6 +202,7 @@ export interface ModuleServiceInitializeOptions { database?: string driverOptions?: Record debug?: boolean + pool?: Record } } diff --git a/packages/utils/package.json b/packages/utils/package.json index c05c3d7dca..04b0292cd7 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -32,6 +32,7 @@ "@mikro-orm/migrations": "5.7.12", "@mikro-orm/postgresql": "5.7.12", "awilix": "^8.0.1", + "knex": "2.4.2", "ulid": "^2.3.0" }, "scripts": { diff --git a/packages/utils/src/dal/mikro-orm/mikro-orm-create-connection.ts b/packages/utils/src/dal/mikro-orm/mikro-orm-create-connection.ts index 3e1d604795..ecfedbc5cc 100644 --- a/packages/utils/src/dal/mikro-orm/mikro-orm-create-connection.ts +++ b/packages/utils/src/dal/mikro-orm/mikro-orm-create-connection.ts @@ -36,5 +36,6 @@ export async function mikroOrmCreateConnection( migrations: { path: pathToMigrations, }, + pool: database.pool as any, }) } diff --git a/packages/utils/src/modules-sdk/create-pg-connection.ts b/packages/utils/src/modules-sdk/create-pg-connection.ts new file mode 100644 index 0000000000..4770c1a35f --- /dev/null +++ b/packages/utils/src/modules-sdk/create-pg-connection.ts @@ -0,0 +1,30 @@ +import knex from "knex" +import { ModuleServiceInitializeOptions } from "@medusajs/types" + +type Options = ModuleServiceInitializeOptions["database"] + +/** + * Create a new knex (pg in the future) connection which can be reused and shared + * @param options + */ +export function createPgConnection(options: Options) { + const { pool, schema = "public", clientUrl, driverOptions } = options + const ssl = options.driverOptions?.ssl ?? false + + return knex({ + client: "pg", + searchPath: schema, + connection: { + connectionString: clientUrl, + ssl, + idle_in_transaction_session_timeout: + (driverOptions?.idle_in_transaction_session_timeout as number) ?? + undefined, // prevent null to be passed + }, + pool: { + // https://knexjs.org/guide/#pool + ...(pool ?? {}), + min: (pool?.min as number) ?? 0, + }, + }) +} diff --git a/packages/utils/src/modules-sdk/index.ts b/packages/utils/src/modules-sdk/index.ts index 7d9cf2fe81..3e318d0aa2 100644 --- a/packages/utils/src/modules-sdk/index.ts +++ b/packages/utils/src/modules-sdk/index.ts @@ -3,3 +3,4 @@ export * from "./decorators" export * from "./build-query" export * from "./retrieve-entity" export * from "./loaders/mikro-orm-connection-loader" +export * from "./create-pg-connection" diff --git a/yarn.lock b/yarn.lock index 3a4666fff4..decfdea626 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6461,7 +6461,6 @@ __metadata: iso8601-duration: ^1.3.0 jest: ^25.5.4 jsonwebtoken: ^9.0.0 - knex: 2.4.2 lodash: ^4.17.21 medusa-core-utils: ^1.2.0 medusa-interfaces: ^1.3.7 @@ -6734,6 +6733,7 @@ __metadata: cross-env: ^5.2.1 express: ^4.18.2 jest: ^29.6.3 + knex: 2.4.2 rimraf: ^5.0.1 ts-jest: ^29.1.1 typescript: ^5.1.6